Reviewed by Maciej.
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Dec 2007 20:11:09 +0000 (20:11 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Dec 2007 20:11:09 +0000 (20:11 +0000)
        http://bugs.webkit.org/show_bug.cgi?id=16511
        Speed up ClassNodeList and NamedNodeList by using the caching mechanism employed by ChildNodeList.
        - This give a ~2.15x speedup on the native test @ http://ejohn.org/apps/classname/

        * dom/ChildNodeList.cpp: Use the caching NodeList constructor to turn on caching.
        (WebCore::ChildNodeList::ChildNodeList):
        * dom/ClassNodeList.cpp:
        (WebCore::ClassNodeList::ClassNodeList):
        * dom/ClassNodeList.h:

        Move getElementsByName and getElementsByClassName to Node so they
        can use easily employ the caching already used by ChildNodeLists.  In the case of
        getElementsByClassName, this reduces code duplication in Element as well
        * dom/Document.cpp:
        * dom/Document.h:

        Move getElementsByClassName to Node.
        * dom/Element.cpp:
        * dom/Element.h:

        * dom/NameNodeList.cpp: Use the caching NodeList constructor to turn on caching.
        (WebCore::NameNodeList::NameNodeList):
        (WebCore::NameNodeList::item):
        * dom/NameNodeList.h:

        Add maps of caches for ClassNodeLists and NameNodeList to NodeListsNodeData.
        * dom/Node.cpp:
        (WebCore::TagNodeList::TagNodeList):
        (WebCore::Node::Node):
        (WebCore::Node::~Node):
        (WebCore::Node::childNodes):
        (WebCore::Node::registerNodeList):
        (WebCore::Node::getElementsByName):
        (WebCore::Node::getElementsByClassName):
        * dom/Node.h: Make m_nodeLists an OwnPtr.  Moved getElementsByName and getElementsByClassName here

        Allow subclasses to choose whether they want to receive the notifications using a new bit.
        * dom/NodeList.cpp:
        (WebCore::NodeList::NodeList):
        * dom/NodeList.h:
        (WebCore::NodeList::needsNotifications):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@28868 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
WebCore/ChangeLog
WebCore/dom/ChildNodeList.cpp
WebCore/dom/ClassNodeList.cpp
WebCore/dom/ClassNodeList.h
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/dom/Element.cpp
WebCore/dom/Element.h
WebCore/dom/NameNodeList.cpp
WebCore/dom/NameNodeList.h
WebCore/dom/Node.cpp
WebCore/dom/Node.h
WebCore/dom/NodeList.cpp
WebCore/dom/NodeList.h

index 5f967627eefff6a6ff29c6fdc16e32252aeaf984..2fba29532710ca737c1b9a4cdfe9e68a267b9bd4 100644 (file)
@@ -1,3 +1,49 @@
+2007-12-19  Sam Weinig  <sam@webkit.org>
+
+        Reviewed by Maciej.
+
+        http://bugs.webkit.org/show_bug.cgi?id=16511
+        Speed up ClassNodeList and NamedNodeList by using the caching mechanism employed by ChildNodeList.
+        - This give a ~2.15x speedup on the native test @ http://ejohn.org/apps/classname/
+
+        * dom/ChildNodeList.cpp: Use the caching NodeList constructor to turn on caching.
+        (WebCore::ChildNodeList::ChildNodeList):
+        * dom/ClassNodeList.cpp:
+        (WebCore::ClassNodeList::ClassNodeList):
+        * dom/ClassNodeList.h:
+
+        Move getElementsByName and getElementsByClassName to Node so they
+        can use easily employ the caching already used by ChildNodeLists.  In the case of 
+        getElementsByClassName, this reduces code duplication in Element as well
+        * dom/Document.cpp:
+        * dom/Document.h:
+
+        Move getElementsByClassName to Node.
+        * dom/Element.cpp:
+        * dom/Element.h:
+
+        * dom/NameNodeList.cpp: Use the caching NodeList constructor to turn on caching.
+        (WebCore::NameNodeList::NameNodeList):
+        (WebCore::NameNodeList::item):
+        * dom/NameNodeList.h:
+
+        Add maps of caches for ClassNodeLists and NameNodeList to NodeListsNodeData.
+        * dom/Node.cpp:
+        (WebCore::TagNodeList::TagNodeList):
+        (WebCore::Node::Node):
+        (WebCore::Node::~Node):
+        (WebCore::Node::childNodes):
+        (WebCore::Node::registerNodeList):
+        (WebCore::Node::getElementsByName):
+        (WebCore::Node::getElementsByClassName):
+        * dom/Node.h: Make m_nodeLists an OwnPtr.  Moved getElementsByName and getElementsByClassName here
+
+        Allow subclasses to choose whether they want to receive the notifications using a new bit.
+        * dom/NodeList.cpp:
+        (WebCore::NodeList::NodeList):
+        * dom/NodeList.h:
+        (WebCore::NodeList::needsNotifications):
+
 2007-12-19  Dave Hyatt  <hyatt@apple.com>
 
         Add support for GDI text rendering to WebKit.
index d394b0a59f3db91846c304f8198cb8d7c00abe3a..a171fecd5e12cd2cf116d071c78dc71d6b5cb64b 100644 (file)
@@ -31,7 +31,7 @@ using namespace WebCore;
 namespace WebCore {
 
 ChildNodeList::ChildNodeList(Node* n, NodeList::Caches* info)
-    : NodeList(n, info)
+    : NodeList(n, info, false)
 {
 }
 
index 390fc35ff717b572f227da3f5152fcc55cfda593..59d976bd630ef3f89f0dfbb8f0db3359e54d73d3 100644 (file)
 
 namespace WebCore {
 
-ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const AtomicString& className)
-    : NodeList(rootNode)
+ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames, NodeList::Caches* caches)
+    : NodeList(rootNode, caches, true)
 {
-    m_classNames.parseClassAttribute(className, m_rootNode->document()->inCompatMode());
+    m_classNames.parseClassAttribute(classNames, m_rootNode->document()->inCompatMode());
 }
 
 unsigned ClassNodeList::length() const
index 1ba05a7915ed3889252d8ab38ed26d19d09b81ca..5c631fcaca5f7c6a73abd22f4781dcd8107fdbfe 100644 (file)
 #ifndef ClassNodeList_h
 #define ClassNodeList_h
 
-#include "AtomicString.h"
 #include "ClassNames.h"
 #include "NodeList.h"
 
 namespace WebCore {
 
+    class String;
+
     class ClassNodeList : public NodeList {
     public:
-        ClassNodeList(PassRefPtr<Node> rootNode, const AtomicString& className);
+        ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames, NodeList::Caches*);
 
         virtual unsigned length() const;
         virtual Node* item(unsigned index) const;
index 825a3390d32774bb01b7e3eadd135d067de9b833..3a47772d71e8ccc2dbb596c155744919a125826d 100644 (file)
@@ -3496,16 +3496,6 @@ HTMLCollection::CollectionInfo* Document::nameCollectionInfo(HTMLCollection::Typ
     return iter->second;
 }
 
-PassRefPtr<NameNodeList> Document::getElementsByName(const String& elementName)
-{
-    return new NameNodeList(this, elementName);
-}
-
-PassRefPtr<NodeList> Document::getElementsByClassName(const String& className)
-{
-    return new ClassNodeList(this, className);
-}
-
 void Document::finishedParsing()
 {
     setParsing(false);
index 1bf52fbd2b29be89ff53b0bc8a68181e8390bf62..5e641500a488a3f463a74c0fa6fb49325592d99c 100644 (file)
@@ -211,9 +211,6 @@ public:
     virtual String baseURI() const;
 
     PassRefPtr<Node> adoptNode(PassRefPtr<Node> source, ExceptionCode&);
-    
-    PassRefPtr<NameNodeList> getElementsByName(const String& elementName);
-    PassRefPtr<NodeList> getElementsByClassName(const String& className);
 
     PassRefPtr<HTMLCollection> images();
     PassRefPtr<HTMLCollection> embeds();
index ecbdf18a70bc9a6b82ca51e2561e4cff1d23a075..cb52e597a6ecd99d87f4bc67d312f6734765b891 100644 (file)
@@ -1123,11 +1123,6 @@ RenderStyle* Element::computedStyle()
     return rd->m_computedStyle;
 }
 
-PassRefPtr<NodeList> Element::getElementsByClassName(const String& className)
-{
-    return new ClassNodeList(this, className);
-}
-
 void Element::cancelFocusAppearanceUpdate()
 {
     if (ElementRareData* rd = rareData())
index 163d54803e306fa7c54fec60fcf29436354688e0..c866028b69aa7cd0922e8f08a12687bbe196477b 100644 (file)
@@ -162,8 +162,6 @@ public:
     virtual void focus(bool restorePreviousSelection = true);
     virtual void updateFocusAppearance(bool restorePreviousSelection);
     void blur();
-    
-    PassRefPtr<NodeList> getElementsByClassName(const String&);
 
 #ifndef NDEBUG
     virtual void dump(TextStream* , DeprecatedString ind = "") const;
index 5fd9eb57d05db7bc59f39e92e31bc4f2fd5f13cb..3d50f85a30f02740d2dbd0c28e2f55b955b30ef7 100644 (file)
@@ -30,8 +30,8 @@ namespace WebCore {
 
 using namespace HTMLNames;
 
-NameNodeList::NameNodeList(Node* root, const String& name)
-    : NodeList(root)
+NameNodeList::NameNodeList(Node* root, const String& name, NodeList::Caches* caches)
+    : NodeList(root, caches, true)
     , m_nodeName(name)
 {
 }
@@ -41,7 +41,7 @@ unsigned NameNodeList::length() const
     return recursiveLength();
 }
 
-Node* NameNodeList::item (unsigned index) const
+Node* NameNodeList::item(unsigned index) const
 {
     return recursiveItem(index);
 }
index aa801e261183d8a4497cf71637af98ba8cd65233..25aaf99d61d8b9a492bef81d2cdc8c75bba828df 100644 (file)
@@ -33,7 +33,7 @@ namespace WebCore {
  */
 class NameNodeList : public NodeList {
 public:
-    NameNodeList(Node* root, const String& name);
+    NameNodeList(Node* root, const String& name, NodeList::Caches*);
 
     // DOM methods overridden from  parent classes
 
@@ -41,6 +41,7 @@ public:
     virtual Node* item(unsigned index) const;
 
     // Other methods (not part of DOM)
+    
     virtual void rootNodeAttributeChanged() { NodeList::rootNodeChildrenChanged(); }
 
 protected:
index dba01bd581e76ecd3e46fec091a7b2091a9fb27b..d1cf842ef0ba4c19a4bedc472e244c6d096180a6 100644 (file)
 
 #include "CString.h"
 #include "ChildNodeList.h"
+#include "ClassNodeList.h"
 #include "DOMImplementation.h"
 #include "Document.h"
 #include "Element.h"
 #include "ExceptionCode.h"
 #include "Frame.h"
 #include "HTMLNames.h"
+#include "HTMLNames.h"
 #include "KURL.h"
 #include "Logging.h"
+#include "NameNodeList.h"
 #include "NamedAttrMap.h"
 #include "RenderObject.h"
 #include "Text.h"
@@ -50,6 +53,8 @@ typedef HashSet<NodeList*> NodeListSet;
 struct NodeListsNodeData {
     NodeListSet m_listsToNotify;
     NodeList::Caches m_childNodeListCaches;
+    HashMap<String, NodeList::Caches> m_classNodeListCaches;
+    HashMap<String, NodeList::Caches> m_nameNodeListCaches;
 };
 
 // NodeList that limits to a particular tag.
@@ -68,7 +73,9 @@ private:
 };
 
 inline TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName)
-    : NodeList(rootNode), m_namespaceURI(namespaceURI), m_localName(localName)
+    : NodeList(rootNode, true)
+    , m_namespaceURI(namespaceURI)
+    , m_localName(localName)
 {
     ASSERT(m_namespaceURI.isNull() || !m_namespaceURI.isEmpty());
 }
@@ -138,7 +145,6 @@ Node::Node(Document *doc)
       m_previous(0),
       m_next(0),
       m_renderer(0),
-      m_nodeLists(0),
       m_tabIndex(0),
       m_hasId(false),
       m_hasClass(false),
@@ -191,7 +197,7 @@ Node::~Node()
 #endif
     if (renderer())
         detach();
-    delete m_nodeLists;
+
     if (m_previous)
         m_previous->setNextSibling(0);
     if (m_next)
@@ -217,7 +223,7 @@ void Node::setNodeValue(const String& /*nodeValue*/, ExceptionCode& ec)
 PassRefPtr<NodeList> Node::childNodes()
 {
     if (!m_nodeLists)
-        m_nodeLists = new NodeListsNodeData;
+        m_nodeLists.set(new NodeListsNodeData);
 
     return new ChildNodeList(this, &m_nodeLists->m_childNodeListCaches);
 }
@@ -438,7 +444,7 @@ unsigned Node::nodeIndex() const
 void Node::registerNodeList(NodeList* list)
 {
     if (!m_nodeLists)
-        m_nodeLists = new NodeListsNodeData;
+        m_nodeLists.set(new NodeListsNodeData);
     else if (!m_document->hasNodeLists())
         // We haven't been receiving notifications while there were no registered lists, so the cache is invalid now.
         m_nodeLists->m_childNodeListCaches.reset();
@@ -1207,6 +1213,22 @@ PassRefPtr<NodeList> Node::getElementsByTagNameNS(const String& namespaceURI, co
     return new TagNodeList(this, namespaceURI.isEmpty() ? nullAtom : AtomicString(namespaceURI), name);
 }
 
+PassRefPtr<NodeList> Node::getElementsByName(const String& elementName)
+{
+    if (!m_nodeLists)
+        m_nodeLists.set(new NodeListsNodeData);
+
+    return new NameNodeList(this, elementName, &m_nodeLists->m_nameNodeListCaches.add(elementName, NodeList::Caches()).first->second);
+}
+
+PassRefPtr<NodeList> Node::getElementsByClassName(const String& classNames)
+{
+    if (!m_nodeLists)
+        m_nodeLists.set(new NodeListsNodeData);
+
+    return new ClassNodeList(this, classNames, &m_nodeLists->m_classNodeListCaches.add(classNames, NodeList::Caches()).first->second);
+}
+
 Document *Node::ownerDocument() const
 {
     Document *doc = document();
index 72886a0c6d997a323e70a748f83ba61f183c20a9..511234f575725bf89d9246ab224b47a104214b98 100644 (file)
 #ifndef Node_h
 #define Node_h
 
-#include "DocPtr.h"
 #include "DeprecatedString.h"
+#include "DocPtr.h"
 #include "PlatformString.h"
 #include "TreeShared.h"
 #include <wtf/Assertions.h>
 #include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
 #include <wtf/PassRefPtr.h>
 
 namespace WebCore {
@@ -44,7 +45,6 @@ class IntRect;
 class KeyboardEvent;
 class NamedAttrMap;
 class NodeList;
-struct NodeListsNodeData;
 class PlatformKeyboardEvent;
 class PlatformMouseEvent;
 class PlatformWheelEvent;
@@ -54,6 +54,7 @@ class RenderArena;
 class RenderObject;
 class RenderStyle;
 class TextStream;
+struct NodeListsNodeData;
 
 typedef int ExceptionCode;
 
@@ -451,6 +452,9 @@ public:
     PassRefPtr<NodeList> getElementsByTagName(const String&);
     PassRefPtr<NodeList> getElementsByTagNameNS(const String& namespaceURI, const String& localName);
 
+    PassRefPtr<NodeList> getElementsByName(const String& elementName);
+    PassRefPtr<NodeList> getElementsByClassName(const String& classNames);
+
 private: // members
     DocPtr<Document> m_document;
     Node* m_previous;
@@ -461,7 +465,7 @@ protected:
     virtual void willMoveToNewOwnerDocument() { }
     virtual void didMoveToNewOwnerDocument() { }
     
-    NodeListsNodeData* m_nodeLists;
+    OwnPtr<NodeListsNodeData> m_nodeLists;
 
     short m_tabIndex;
 
index e0c0eecf3f27be05f47140774208e9f17421e8f2..a44d0e32efe990ca865b41daba198a77ed77a139 100644 (file)
 
 namespace WebCore {
 
-NodeList::NodeList(PassRefPtr<Node> rootNode)
+NodeList::NodeList(PassRefPtr<Node> rootNode, bool needsNotifications)
     : m_rootNode(rootNode)
     , m_caches(new Caches)
     , m_ownsCaches(true)
+    , m_needsNotifications(needsNotifications)
 {
     m_rootNode->registerNodeList(this);
 }    
 
-NodeList::NodeList(PassRefPtr<Node> rootNode, NodeList::Caches* info)
+NodeList::NodeList(PassRefPtr<Node> rootNode, NodeList::Caches* info, bool needsNotifications)
     : m_rootNode(rootNode)
     , m_caches(info)
     , m_ownsCaches(false)
+    , m_needsNotifications(needsNotifications)
 {
     m_rootNode->registerNodeList(this);
 }    
index cf531c215d9a7c84d6fc784e9abc49252d91129c..8843fe2b031e94c486a9b07eadd5bed258c786ac 100644 (file)
@@ -49,11 +49,11 @@ public:
         bool isItemCacheValid : 1;
     };
 
-    NodeList(PassRefPtr<Node> rootNode);
-    NodeList(PassRefPtr<Node> rootNode, Caches*);
+    NodeList(PassRefPtr<Node> rootNode, bool needsNotifications);
+    NodeList(PassRefPtr<Node> rootNode, Caches*, bool needsNotifications);
     virtual ~NodeList();
 
-    bool needsNotifications() const { return m_ownsCaches; }
+    bool needsNotifications() const { return m_needsNotifications; }
 
     // DOM methods & attributes for NodeList
     virtual unsigned length() const = 0;
@@ -73,6 +73,7 @@ protected:
     RefPtr<Node> m_rootNode;
     mutable Caches* m_caches;
     bool m_ownsCaches;
+    bool m_needsNotifications;
 
  private:
     Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;