Cache and reuse the NodeList returned by Node::childNodes().
authorkling@webkit.org <kling@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Jan 2012 02:55:03 +0000 (02:55 +0000)
committerkling@webkit.org <kling@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Jan 2012 02:55:03 +0000 (02:55 +0000)
commitb255f609067229c7faa3289d9469930652205bcf
tree086bd6914d0fd9bf2a9a88fe15ed00597adac7c6
parente8ea7849fbf01a95814043333ec9881067c21049
Cache and reuse the NodeList returned by Node::childNodes().
<http://webkit.org/b/76591>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Instead of only caching the DynamicNodeList::Caches for .childNodes on NodeRareData,
cache the full ChildNodeList object. Lifetime management is left to wrappers who
invalidate the cached (raw) pointer via Node::removeCachedChildNodeList(), called
from ~ChildNodeList().

This is a slight behavior change, in that Node.childNodes === Node.childNodes will
now be true. This matches the behavior of both Firefox and Opera.

This reduces memory consumption by 192 kB (on 32-bit) when viewing the full
HTML5 spec at <http://whatwg.org/c>

Test: fast/dom/gc-9.html
      fast/dom/node-childNodes-idempotence.html

* dom/Node.cpp:
(WebCore::Node::childNodes):
* dom/NodeRareData.h:
(WebCore::NodeRareData::NodeRareData):
(WebCore::NodeRareData::childNodeList):
(WebCore::NodeRareData::setChildNodeList):

    Only construct one ChildNodeList per Node and store it on NodeRareData for
    retrieval across childNodes() calls.

* dom/ChildNodeList.h:
(WebCore::ChildNodeList::create):
* dom/ChildNodeList.cpp:
(WebCore::ChildNodeList::ChildNodeList):

    Construct the Caches at creation instead of passing it to the constructor.

(WebCore::ChildNodeList::reset):

    Added, resets the internal cache.

(WebCore::ChildNodeList::~ChildNodeList):

    Call Node::removeCachedChildNodeList().

* dom/DynamicNodeList.cpp:
* dom/DynamicNodeList.h:

    Have DynamicNodeList (and subclasses) respond "true" to isDynamicNodeList().
    Previously only DynamicSubtreeNodeList (and subclasses) were doing this.
    Without it, JSC may GC our ChildNodeLists prematurely (due to NodeList's
    isReachableFromOpaqueRoots() implementation checking isDynamicNodeList().)

* dom/Node.h:
* dom/Node.cpp:
(WebCore::Node::removeCachedChildNodeList):

    Added for ~ChildNodeList() to remove the pointer to itself from the Node.

(WebCore::NodeRareData::clearChildNodeListCache):

    Call ChildNodeList::reset().

LayoutTests:

Updated gc-9.html to document the new lifetime characteristics of a .childNodes with
custom properties. Also added a test to verify that .childNodes === .childNodes.

* fast/dom/gc-9-expected.txt:
* fast/dom/gc-9.html:
* fast/dom/node-childNodes-idempotence-expected.txt: Added.
* fast/dom/node-childNodes-idempotence.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@105372 268f45cc-cd09-0410-ab3c-d52691b4dbfc
13 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/gc-9-expected.txt
LayoutTests/fast/dom/gc-9.html
LayoutTests/fast/dom/node-childNodes-idempotence-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/node-childNodes-idempotence.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/ChildNodeList.cpp
Source/WebCore/dom/ChildNodeList.h
Source/WebCore/dom/DynamicNodeList.cpp
Source/WebCore/dom/DynamicNodeList.h
Source/WebCore/dom/Node.cpp
Source/WebCore/dom/Node.h
Source/WebCore/dom/NodeRareData.h