Changeset 21003 in webkit


Ignore:
Timestamp:
Apr 22, 2007 1:23:55 AM (17 years ago)
Author:
ap
Message:

Reviewed by Darin.

http://bugs.webkit.org/show_bug.cgi?id=13115
REGRESSION: 1000% performance regression in DOM access by index, which was already slow

  • dom/NodeList.h: Move cached data into a separate class, so it can be shared.
  • dom/Node.h: Replace the set of registered NodeLists with a struct that also contains a shared NodeList::Caches (so the size of Node doesn't change).
  • dom/NodeList.cpp: (WebCore::NodeList::NodeList): (WebCore::NodeList::~NodeList): (WebCore::NodeList::recursiveLength): (WebCore::NodeList::itemForwardsFromCurrent): (WebCore::NodeList::itemBackwardsFromCurrent): (WebCore::NodeList::recursiveItem): (WebCore::NodeList::itemWithName): (WebCore::NodeList::rootNodeChildrenChanged): (WebCore::NodeList::NodeListInfo::NodeListInfo): (WebCore::NodeList::NodeListInfo::reset):
  • dom/ChildNodeList.cpp: (WebCore::ChildNodeList::ChildNodeList): (WebCore::ChildNodeList::length): (WebCore::ChildNodeList::item): (WebCore::ChildNodeList::nodeMatches):
  • dom/ChildNodeList.h:
  • dom/Node.cpp: (WebCore::Node::childNodes): (WebCore::Node::registerNodeList): (WebCore::Node::unregisterNodeList): (WebCore::Node::notifyLocalNodeListsAttributeChanged): (WebCore::Node::notifyLocalNodeListsChildrenChanged): Adjust for the above changes.
Location:
trunk/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r21002 r21003  
     12007-04-22  Alexey Proskuryakov  <ap@webkit.org>
     2
     3        Reviewed by Darin.
     4
     5        http://bugs.webkit.org/show_bug.cgi?id=13115
     6        REGRESSION: 1000% performance regression in DOM access by index, which was already slow
     7
     8        * dom/NodeList.h: Move cached data into a separate class, so it can be shared.
     9
     10        * dom/Node.h: Replace the set of registered NodeLists with a struct that also
     11        contains a shared NodeList::Caches (so the size of Node doesn't change).
     12
     13        * dom/NodeList.cpp:
     14        (WebCore::NodeList::NodeList):
     15        (WebCore::NodeList::~NodeList):
     16        (WebCore::NodeList::recursiveLength):
     17        (WebCore::NodeList::itemForwardsFromCurrent):
     18        (WebCore::NodeList::itemBackwardsFromCurrent):
     19        (WebCore::NodeList::recursiveItem):
     20        (WebCore::NodeList::itemWithName):
     21        (WebCore::NodeList::rootNodeChildrenChanged):
     22        (WebCore::NodeList::NodeListInfo::NodeListInfo):
     23        (WebCore::NodeList::NodeListInfo::reset):
     24        * dom/ChildNodeList.cpp:
     25        (WebCore::ChildNodeList::ChildNodeList):
     26        (WebCore::ChildNodeList::length):
     27        (WebCore::ChildNodeList::item):
     28        (WebCore::ChildNodeList::nodeMatches):
     29        * dom/ChildNodeList.h:
     30        * dom/Node.cpp:
     31        (WebCore::Node::childNodes):
     32        (WebCore::Node::registerNodeList):
     33        (WebCore::Node::unregisterNodeList):
     34        (WebCore::Node::notifyLocalNodeListsAttributeChanged):
     35        (WebCore::Node::notifyLocalNodeListsChildrenChanged):
     36        Adjust for the above changes.
     37
    1382007-04-21  Mitz Pettel  <mitz@webkit.org>
    239
  • trunk/WebCore/dom/ChildNodeList.cpp

    r20214 r21003  
    3131namespace WebCore {
    3232
    33 ChildNodeList::ChildNodeList( Node *n )
    34     : NodeList(n)
     33ChildNodeList::ChildNodeList(Node* n, NodeList::Caches* info)
     34    : NodeList(n, info)
    3535{
    3636}
     
    3838unsigned ChildNodeList::length() const
    3939{
    40     if (isLengthCacheValid)
    41         return cachedLength;
     40    if (m_caches->isLengthCacheValid)
     41        return m_caches->cachedLength;
    4242
    4343    unsigned len = 0;
    4444    Node *n;
    45     for(n = rootNode->firstChild(); n != 0; n = n->nextSibling())
     45    for (n = m_rootNode->firstChild(); n != 0; n = n->nextSibling())
    4646        len++;
    4747
    48     cachedLength = len;
    49     isLengthCacheValid = true;
     48    m_caches->cachedLength = len;
     49    m_caches->isLengthCacheValid = true;
    5050
    5151    return len;
    5252}
    5353
    54 Node *ChildNodeList::item ( unsigned index ) const
     54Node *ChildNodeList::item(unsigned index) const
    5555{
    5656    unsigned int pos = 0;
    57     Node *n = rootNode->firstChild();
     57    Node *n = m_rootNode->firstChild();
    5858
    59     if (isItemCacheValid) {
    60         if (index == lastItemOffset) {
    61             return lastItem;
    62         } else if (index > lastItemOffset) {
    63             n = lastItem;
    64             pos = lastItemOffset;
     59    if (m_caches->isItemCacheValid) {
     60        if (index == m_caches->lastItemOffset)
     61            return m_caches->lastItem;
     62        if (index > m_caches->lastItemOffset) {
     63            n = m_caches->lastItem;
     64            pos = m_caches->lastItemOffset;
    6565        }
    6666    }
     
    7272
    7373    if (n) {
    74         lastItem = n;
    75         lastItemOffset = pos;
    76         isItemCacheValid = true;
     74        m_caches->lastItem = n;
     75        m_caches->lastItemOffset = pos;
     76        m_caches->isItemCacheValid = true;
    7777        return n;
    7878    }
     
    8383bool ChildNodeList::nodeMatches(Node *testNode) const
    8484{
    85     return testNode->parentNode() == rootNode;
     85    return testNode->parentNode() == m_rootNode;
    8686}
    8787
  • trunk/WebCore/dom/ChildNodeList.h

    r20214 r21003  
    3232class ChildNodeList : public NodeList {
    3333public:
    34     ChildNodeList(Node*);
     34    ChildNodeList(Node*, NodeList::Caches*);
    3535
    3636    virtual unsigned length() const;
  • trunk/WebCore/dom/Node.cpp

    r20997 r21003  
    4848using namespace HTMLNames;
    4949
     50typedef HashSet<NodeList*> NodeListSet;
     51struct NodeListsNodeData {
     52    NodeListSet m_registeredLists;
     53    NodeList::Caches m_childNodeListCaches;
     54};
     55
     56
    5057/**
    5158 * NodeList which lists all Nodes in a document with a given tag name
     
    216223PassRefPtr<NodeList> Node::childNodes()
    217224{
    218     return new ChildNodeList(this);
     225    if (!m_nodeLists)
     226        m_nodeLists = new NodeListsNodeData;
     227
     228    return new ChildNodeList(this, &m_nodeLists->m_childNodeListCaches);
    219229}
    220230
     
    431441{
    432442    if (!m_nodeLists)
    433         m_nodeLists = new NodeListSet;
    434     m_nodeLists->add(list);
     443        m_nodeLists = new NodeListsNodeData;
     444    m_nodeLists->m_registeredLists.add(list);
    435445}
    436446
     
    439449    if (!m_nodeLists)
    440450        return;
    441     m_nodeLists->remove(list);
     451    m_nodeLists->m_registeredLists.remove(list);
    442452}
    443453
     
    447457        return;
    448458
    449     NodeListSet::iterator end = m_nodeLists->end();
    450     for (NodeListSet::iterator i = m_nodeLists->begin(); i != end; ++i)
     459    NodeListSet::iterator end = m_nodeLists->m_registeredLists.end();
     460    for (NodeListSet::iterator i = m_nodeLists->m_registeredLists.begin(); i != end; ++i)
    451461        (*i)->rootNodeAttributeChanged();
    452462}
     
    463473        return;
    464474
    465     NodeListSet::iterator end = m_nodeLists->end();
    466     for (NodeListSet::iterator i = m_nodeLists->begin(); i != end; ++i)
     475    NodeListSet::iterator end = m_nodeLists->m_registeredLists.end();
     476    for (NodeListSet::iterator i = m_nodeLists->m_registeredLists.begin(); i != end; ++i)
    467477        (*i)->rootNodeChildrenChanged();
    468478}
  • trunk/WebCore/dom/Node.h

    r20214 r21003  
    4646class NamedAttrMap;
    4747class NodeList;
     48struct NodeListsNodeData;
    4849class PlatformKeyboardEvent;
    4950class PlatformMouseEvent;
     
    457458
    458459protected:
    459     typedef HashSet<NodeList*> NodeListSet;
    460     NodeListSet* m_nodeLists;
     460    NodeListsNodeData* m_nodeLists;
    461461
    462462    short m_tabIndex;
  • trunk/WebCore/dom/NodeList.cpp

    r20214 r21003  
    3131namespace WebCore {
    3232
    33 NodeList::NodeList(PassRefPtr<Node> _rootNode)
    34     : rootNode(_rootNode),
    35       isLengthCacheValid(false),
    36       isItemCacheValid(false)
     33NodeList::NodeList(PassRefPtr<Node> rootNode)
     34    : m_rootNode(rootNode)
     35    , m_caches(new Caches)
     36    , m_ownsCaches(true)
    3737{
    38     rootNode->registerNodeList(this);
     38    m_rootNode->registerNodeList(this);
     39}   
     40
     41NodeList::NodeList(PassRefPtr<Node> rootNode, NodeList::Caches* info)
     42    : m_rootNode(rootNode)
     43    , m_caches(info)
     44    , m_ownsCaches(false)
     45{
     46    m_rootNode->registerNodeList(this);
    3947}   
    4048
    4149NodeList::~NodeList()
    4250{
    43     rootNode->unregisterNodeList(this);
     51    m_rootNode->unregisterNodeList(this);
     52    if (m_ownsCaches)
     53        delete m_caches;
    4454}
    4555
     
    4757{
    4858    if (!start)
    49         start = rootNode.get();
     59        start = m_rootNode.get();
    5060
    51     if (isLengthCacheValid && start == rootNode)
    52         return cachedLength;
     61    if (m_caches->isLengthCacheValid && start == m_rootNode)
     62        return m_caches->cachedLength;
    5363
    5464    unsigned len = 0;
     
    6171        }
    6272
    63     if (start == rootNode) {
    64         cachedLength = len;
    65         isLengthCacheValid = true;
     73    if (start == m_rootNode) {
     74        m_caches->cachedLength = len;
     75        m_caches->isLengthCacheValid = true;
    6676    }
    6777
     
    7383    ASSERT(remainingOffset >= 0);
    7484
    75     for (Node *n = start; n; n = n->traverseNextNode(rootNode.get())) {
     85    for (Node *n = start; n; n = n->traverseNextNode(m_rootNode.get())) {
    7686        if (n->isElementNode()) {
    7787            if (nodeMatches(n)) {
    7888                if (!remainingOffset) {
    79                     lastItem = n;
    80                     lastItemOffset = offset;
    81                     isItemCacheValid = true;
     89                    m_caches->lastItem = n;
     90                    m_caches->lastItemOffset = offset;
     91                    m_caches->isItemCacheValid = true;
    8292                    return n;
    8393                }
     
    93103{
    94104    ASSERT(remainingOffset < 0);
    95     for (Node *n = start; n; n = n->traversePreviousNode(rootNode.get())) {
     105    for (Node *n = start; n; n = n->traversePreviousNode(m_rootNode.get())) {
    96106        if (n->isElementNode()) {
    97107            if (nodeMatches(n)) {
    98108                if (!remainingOffset) {
    99                     lastItem = n;
    100                     lastItemOffset = offset;
    101                     isItemCacheValid = true;
     109                    m_caches->lastItem = n;
     110                    m_caches->lastItemOffset = offset;
     111                    m_caches->isItemCacheValid = true;
    102112                    return n;
    103113                }
     
    114124    int remainingOffset = offset;
    115125    if (!start) {
    116         start = rootNode->firstChild();
    117         if (isItemCacheValid) {
    118             if (offset == lastItemOffset) {
    119                 return lastItem;
    120             } else if (offset > lastItemOffset || lastItemOffset - offset < offset) {
    121                 start = lastItem;
    122                 remainingOffset -= lastItemOffset;
     126        start = m_rootNode->firstChild();
     127        if (m_caches->isItemCacheValid) {
     128            if (offset == m_caches->lastItemOffset) {
     129                return m_caches->lastItem;
     130            } else if (offset > m_caches->lastItemOffset || m_caches->lastItemOffset - offset < offset) {
     131                start = m_caches->lastItem;
     132                remainingOffset -= m_caches->lastItemOffset;
    123133            }
    124134        }
     
    133143Node* NodeList::itemWithName(const AtomicString& elementId) const
    134144{
    135     if (rootNode->isDocumentNode() || rootNode->inDocument()) {
    136         Node* node = rootNode->document()->getElementById(elementId);
     145    if (m_rootNode->isDocumentNode() || m_rootNode->inDocument()) {
     146        Node* node = m_rootNode->document()->getElementById(elementId);
    137147
    138148        if (!node || !nodeMatches(node))
     
    140150
    141151        for (Node* p = node->parentNode(); p; p = p->parentNode())
    142             if (p == rootNode)
     152            if (p == m_rootNode)
    143153                return node;
    144154
     
    158168void NodeList::rootNodeChildrenChanged()
    159169{
     170    m_caches->reset();
     171}
     172
     173
     174NodeList::Caches::Caches()
     175    : lastItem(0)
     176    , isLengthCacheValid(false)
     177    , isItemCacheValid(false)
     178{
     179}
     180
     181void NodeList::Caches::reset()
     182{
     183    lastItem = 0;
    160184    isLengthCacheValid = false;
    161185    isItemCacheValid = false;     
    162     lastItem = 0;
    163186}
    164187
  • trunk/WebCore/dom/NodeList.h

    r20214 r21003  
    3838class NodeList : public Shared<NodeList> {
    3939public:
     40
     41    struct Caches {
     42        Caches();
     43        void reset();
     44       
     45        int cachedLength;
     46        Node* lastItem;
     47        unsigned lastItemOffset;
     48        bool isLengthCacheValid : 1;
     49        bool isItemCacheValid : 1;
     50    };
     51
    4052    NodeList(PassRefPtr<Node> rootNode);
     53    NodeList(PassRefPtr<Node> rootNode, Caches*);
    4154    virtual ~NodeList();
    4255
     
    5669    virtual bool nodeMatches(Node* testNode) const = 0;
    5770
    58     RefPtr<Node> rootNode;
    59     mutable int cachedLength;
    60     mutable Node* lastItem;
    61     mutable unsigned lastItemOffset;
    62     mutable bool isLengthCacheValid : 1;
    63     mutable bool isItemCacheValid : 1;
     71    RefPtr<Node> m_rootNode;
     72    mutable Caches* m_caches;
     73    bool m_ownsCaches;
    6474
    6575 private:
Note: See TracChangeset for help on using the changeset viewer.