Changeset 122518 in webkit


Ignore:
Timestamp:
Jul 12, 2012 3:40:26 PM (12 years ago)
Author:
rniwa@webkit.org
Message:

Merge HTMLCollectionWithArrayStorage into HTMLCollection
https://bugs.webkit.org/show_bug.cgi?id=91144

Reviewed by Anders Carlsson.

Merged HTMLCollectionWithArrayStorage::item into HTMLCollection::item and got rid of
HTMLCollectionWithArrayStorage. Also de-virtualized HTMLCollection::item and HTMLCollection::length
and merged itemInArrayAfter and itemAfter.

In addition, improved the algorithm in HTMLCollection::length to take advantage of item cache.
Instead of always computing the length from the beginning, we start the search from the cached item
so that if we're near end of the collection, we avoid significant portion of the node traversal.

Furthermore, made HTMLCollection always call setItemCache with a non-null item and HTMLCollection::item
set the length cache when it reaches the end of the collection to avoid redundant length calculations.

  • dom/DynamicNodeList.h:

(WebCore::DynamicNodeListCacheBase::setItemCache): Add a FIXME.

  • html/HTMLCollection.cpp:

(WebCore::HTMLCollection::itemAfter): Regular HTMLCollection doesn't have uses elements array so
assert that offsetInArray is always 0.
(WebCore): Removed calcLength.
(WebCore::HTMLCollection::length): Rewritten. The algorithm is as follows:
When there is no item cache, we look for the first item by calling item(0). If item(0) returns null,
then it must have set the length cache so bail out. If the previous step didn't bail out, then
the item cache is valid and not null (see above), so count the number of remaining items in collection
starting at the cached item's offset + 1.
(WebCore::HTMLCollection::item): Avoid calling setItemCache with null. When the first item is null,
set the length cache instead.
(WebCore::HTMLCollection::itemAfterCachedItem): Extracted from HTMLCollectionWithArrayStorage::item.
(WebCore::HTMLCollection::namedItem): Pass in arrayOffset to itemAfter. Note this variable is never
used since only HTMLFormCollection and HTMLPropertiesCollection use array offsets but they override
this function.
(WebCore::HTMLCollection::updateNameCache): Ditto.

  • html/HTMLCollection.h:

(HTMLCollection):
(WebCore):

  • html/HTMLFormCollection.cpp: Removed calcLength(). Even though this function didn't iterate over

the collection directly, HTMLFormElement::length and HTMLFieldSetElement::length did so we're not
regressing any performance here.
(WebCore::HTMLFormCollection::HTMLFormCollection):
(WebCore::HTMLFormCollection::itemAfter):

  • html/HTMLFormCollection.h:

(HTMLFormCollection):

  • html/HTMLNameCollection.cpp:

(WebCore::HTMLNameCollection::itemAfter):

  • html/HTMLNameCollection.h:

(HTMLNameCollection):

  • html/HTMLPropertiesCollection.cpp: Removed calcLength().

(WebCore::HTMLPropertiesCollection::HTMLPropertiesCollection):
(WebCore::HTMLPropertiesCollection::itemAfter):
(WebCore):

  • html/HTMLPropertiesCollection.h:

(HTMLPropertiesCollection):

  • html/HTMLTableRowsCollection.cpp:

(WebCore::HTMLTableRowsCollection::itemAfter):

  • html/HTMLTableRowsCollection.h:

(HTMLTableRowsCollection):

Location:
trunk/Source/WebCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r122516 r122518  
     12012-07-12  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Merge HTMLCollectionWithArrayStorage into HTMLCollection
     4        https://bugs.webkit.org/show_bug.cgi?id=91144
     5
     6        Reviewed by Anders Carlsson.
     7
     8        Merged HTMLCollectionWithArrayStorage::item into HTMLCollection::item and got rid of
     9        HTMLCollectionWithArrayStorage. Also de-virtualized HTMLCollection::item and HTMLCollection::length
     10        and merged itemInArrayAfter and itemAfter.
     11
     12        In addition, improved the algorithm in HTMLCollection::length to take advantage of item cache.
     13        Instead of always computing the length from the beginning, we start the search from the cached item
     14        so that if we're near end of the collection, we avoid significant portion of the node traversal.
     15
     16        Furthermore, made HTMLCollection always call setItemCache with a non-null item and HTMLCollection::item
     17        set the length cache when it reaches the end of the collection to avoid redundant length calculations.
     18
     19        * dom/DynamicNodeList.h:
     20        (WebCore::DynamicNodeListCacheBase::setItemCache): Add a FIXME.
     21        * html/HTMLCollection.cpp:
     22        (WebCore::HTMLCollection::itemAfter): Regular HTMLCollection doesn't have uses elements array so
     23        assert that offsetInArray is always 0.
     24        (WebCore): Removed calcLength.
     25        (WebCore::HTMLCollection::length): Rewritten. The algorithm is as follows:
     26        When there is no item cache, we look for the first item by calling item(0). If item(0) returns null,
     27        then it must have set the length cache so bail out. If the previous step didn't bail out, then
     28        the item cache is valid and not null (see above), so count the number of remaining items in collection
     29        starting at the cached item's offset + 1.
     30        (WebCore::HTMLCollection::item): Avoid calling setItemCache with null. When the first item is null,
     31        set the length cache instead.
     32        (WebCore::HTMLCollection::itemAfterCachedItem): Extracted from HTMLCollectionWithArrayStorage::item.
     33        (WebCore::HTMLCollection::namedItem): Pass in arrayOffset to itemAfter. Note this variable is never
     34        used since only HTMLFormCollection and HTMLPropertiesCollection use array offsets but they override
     35        this function.
     36        (WebCore::HTMLCollection::updateNameCache): Ditto.
     37        * html/HTMLCollection.h:
     38        (HTMLCollection):
     39        (WebCore):
     40        * html/HTMLFormCollection.cpp: Removed calcLength(). Even though this function didn't iterate over
     41        the collection directly, HTMLFormElement::length and HTMLFieldSetElement::length did so we're not
     42        regressing any performance here.
     43        (WebCore::HTMLFormCollection::HTMLFormCollection):
     44        (WebCore::HTMLFormCollection::itemAfter):
     45        * html/HTMLFormCollection.h:
     46        (HTMLFormCollection):
     47        * html/HTMLNameCollection.cpp:
     48        (WebCore::HTMLNameCollection::itemAfter):
     49        * html/HTMLNameCollection.h:
     50        (HTMLNameCollection):
     51        * html/HTMLPropertiesCollection.cpp: Removed calcLength().
     52        (WebCore::HTMLPropertiesCollection::HTMLPropertiesCollection):
     53        (WebCore::HTMLPropertiesCollection::itemAfter):
     54        (WebCore):
     55        * html/HTMLPropertiesCollection.h:
     56        (HTMLPropertiesCollection):
     57        * html/HTMLTableRowsCollection.cpp:
     58        (WebCore::HTMLTableRowsCollection::itemAfter):
     59        * html/HTMLTableRowsCollection.h:
     60        (HTMLTableRowsCollection):
     61
    1622012-07-12  Pravin D  <pravind.2k4@gmail.com>
    263
  • trunk/Source/WebCore/dom/DynamicNodeList.h

    r122498 r122518  
    6565    ALWAYS_INLINE void setItemCache(Node* item, unsigned offset) const
    6666    {
     67        // FIXME: Assert that item is not null once we've updated DynamicNodeList.
    6768        m_cachedItem = item;
    6869        m_cachedItemOffset = offset;
  • trunk/Source/WebCore/html/HTMLCollection.cpp

    r122353 r122518  
    181181}
    182182
    183 Element* HTMLCollection::itemAfter(Node* previous) const
    184 {
     183Element* HTMLCollection::itemAfter(unsigned& offsetInArray, Element* previous) const
     184{
     185    ASSERT_UNUSED(offsetInArray, !offsetInArray);
    185186    Node* current;
    186187    if (!previous)
     
    200201}
    201202
    202 unsigned HTMLCollection::calcLength() const
    203 {
    204     unsigned len = 0;
    205     for (Element* current = itemAfter(0); current; current = itemAfter(current))
    206         ++len;
    207     return len;
    208 }
    209 
    210 // since the collections are to be "live", we have to do the
    211 // calculation every time if anything has changed
    212203unsigned HTMLCollection::length() const
    213204{
    214205    invalidateCacheIfNeeded();
    215     if (!isLengthCacheValid())
    216         setLengthCache(calcLength());
    217     return cachedLength();
     206    if (isLengthCacheValid())
     207        return cachedLength();
     208
     209    if (!isItemCacheValid() && !item(0)) {
     210        ASSERT(isLengthCacheValid());
     211        return 0;
     212    }
     213
     214    ASSERT(isItemCacheValid());
     215    ASSERT(cachedItem());
     216    unsigned offset = cachedItemOffset();
     217    do {
     218        offset++;
     219    } while (itemAfterCachedItem(offset));
     220
     221    setLengthCache(offset);
     222    return offset;
    218223}
    219224
    220225Node* HTMLCollection::item(unsigned index) const
    221 {
    222     invalidateCacheIfNeeded();
    223     if (isItemCacheValid() && cachedItemOffset() == index)
    224         return cachedItem();
    225     if (isLengthCacheValid() && cachedLength() <= index)
    226         return 0;
    227     if (!isItemCacheValid() || cachedItemOffset() > index) {
    228         setItemCache(itemAfter(0), 0);
    229         if (!cachedItem())
    230             return 0;
    231     }
    232     Node* e = cachedItem();
    233     for (unsigned pos = cachedItemOffset(); e && pos < index; pos++)
    234         e = itemAfter(e);
    235     setItemCache(e, index);
    236     return cachedItem();
    237 }
    238 
    239 Node* HTMLCollectionWithArrayStorage::item(unsigned index) const
    240226{
    241227    invalidateCacheIfNeeded();
     
    253239    if (!isItemCacheValid() || cachedItemOffset() > index) {
    254240        unsigned offsetInArray = 0;
    255         setItemCache(itemInArrayAfter(offsetInArray, 0), 0, 0);
    256         ASSERT(isItemCacheValid());
    257         if (!cachedItem() || cachedItemOffset() == index)
     241        Node* firstItem = itemAfter(offsetInArray, 0);
     242        if (!firstItem) {
     243            setLengthCache(0);
     244            return 0;
     245        }
     246        setItemCache(firstItem, 0, offsetInArray);
     247        ASSERT(!cachedItemOffset());
     248        if (!index)
    258249            return cachedItem();
    259250    }
    260251
     252    return itemAfterCachedItem(index);
     253}
     254
     255Element* HTMLCollection::itemAfterCachedItem(unsigned index) const
     256{
    261257    unsigned currentIndex = cachedItemOffset();
    262     ASSERT(cachedItem()->isHTMLElement());
    263     HTMLElement* currentItem = toHTMLElement(cachedItem());
     258    ASSERT(cachedItem()->isElementNode());
     259    Element* currentItem = toElement(cachedItem());
    264260    ASSERT(currentIndex < index);
    265261
    266262    unsigned offsetInArray = cachedElementsArrayOffset();
    267     while ((currentItem = itemInArrayAfter(offsetInArray, currentItem))) {
     263    while ((currentItem = itemAfter(offsetInArray, currentItem))) {
    268264        currentIndex++;
    269265        if (currentIndex == index) {
    270266            setItemCache(currentItem, currentIndex, offsetInArray);
    271             return cachedItem();
     267            return currentItem;
    272268        }
    273269    }
     
    315311    invalidateCacheIfNeeded();
    316312
     313    unsigned arrayOffset = 0;
    317314    unsigned i = 0;
    318     for (Element* e = itemAfter(0); e; e = itemAfter(e)) {
     315    for (Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {
    319316        if (checkForNameMatch(e, /* checkName */ false, name)) {
    320             setItemCache(e, i);
     317            setItemCache(e, i, arrayOffset);
    321318            return e;
    322319        }
     
    325322
    326323    i = 0;
    327     for (Element* e = itemAfter(0); e; e = itemAfter(e)) {
     324    for (Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {
    328325        if (checkForNameMatch(e, /* checkName */ true, name)) {
    329             setItemCache(e, i);
     326            setItemCache(e, i, arrayOffset);
    330327            return e;
    331328        }
     
    342339        return;
    343340
    344     for (Element* element = itemAfter(0); element; element = itemAfter(element)) {
     341    unsigned arrayOffset = 0;
     342    for (Element* element = itemAfter(arrayOffset, 0); element; element = itemAfter(arrayOffset, element)) {
    345343        if (!element->isHTMLElement())
    346344            continue;
  • trunk/Source/WebCore/html/HTMLCollection.h

    r122498 r122518  
    6464    }
    6565
    66     using DynamicNodeListCacheBase::setItemCache;
    6766    void setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const
    6867    {
     
    9089    using DynamicNodeListCacheBase::shouldInvalidateOnAttributeChange;
    9190    using DynamicNodeListCacheBase::clearCache;
     91    using DynamicNodeListCacheBase::setItemCache;
    9292
    9393    mutable NodeCacheMap m_idCache;
     
    109109    // DOM API
    110110    unsigned length() const;
    111     virtual Node* item(unsigned index) const;
     111    Node* item(unsigned index) const;
    112112    virtual Node* namedItem(const AtomicString& name) const;
    113113    PassRefPtr<NodeList> tags(const String&);
     
    144144
    145145    virtual void updateNameCache() const;
    146     virtual Element* itemAfter(Node*) const;
     146    virtual Element* itemAfter(unsigned& offsetInArray, Element*) const;
    147147
    148148private:
    149149    bool checkForNameMatch(Element*, bool checkName, const AtomicString& name) const;
    150150
    151     virtual unsigned calcLength() const;
    152 
     151    Element* itemAfterCachedItem(unsigned) const;
    153152    bool isAcceptableElement(Element*) const;
    154153
     
    156155};
    157156
    158 class HTMLCollectionWithArrayStorage : public HTMLCollection {
    159 public:
    160     HTMLCollectionWithArrayStorage(Node* base, CollectionType type)
    161         : HTMLCollection(base, type)
    162     { }
    163 
    164     virtual Node* item(unsigned index) const OVERRIDE;
    165 
    166 private:
    167     virtual HTMLElement* itemInArrayAfter(unsigned& offsetInArray, HTMLElement* previousItem) const = 0;
    168 };
    169 
    170157} // namespace
    171158
  • trunk/Source/WebCore/html/HTMLFormCollection.cpp

    r122353 r122518  
    3838
    3939HTMLFormCollection::HTMLFormCollection(Element* base)
    40     : HTMLCollectionWithArrayStorage(base, FormControls)
     40    : HTMLCollection(base, FormControls)
    4141{
    4242    ASSERT(base->hasTagName(formTag) || base->hasTagName(fieldsetTag));
     
    6868}
    6969
    70 unsigned HTMLFormCollection::calcLength() const
    71 {
    72     ASSERT(base()->hasTagName(formTag) || base()->hasTagName(fieldsetTag));
    73     if (base()->hasTagName(formTag))
    74         return static_cast<HTMLFormElement*>(base())->length();
    75     return static_cast<HTMLFieldSetElement*>(base())->length();
    76 }
    77 
    78 HTMLElement* HTMLFormCollection::itemInArrayAfter(unsigned& offset, HTMLElement* previousItem) const
     70Element* HTMLFormCollection::itemAfter(unsigned& offset, Element* previousItem) const
    7971{
    8072    const Vector<FormAssociatedElement*>& elementsArray = formControlElements();
  • trunk/Source/WebCore/html/HTMLFormCollection.h

    r122353 r122518  
    3535// The famous <table><tr><form><td> problem.
    3636
    37 class HTMLFormCollection : public HTMLCollectionWithArrayStorage {
     37class HTMLFormCollection : public HTMLCollection {
    3838public:
    3939    static PassRefPtr<HTMLFormCollection> create(Element*);
     
    4747
    4848    virtual void updateNameCache() const;
    49     virtual unsigned calcLength() const;
    5049
    5150    const Vector<FormAssociatedElement*>& formControlElements() const;
    5251    const Vector<HTMLImageElement*>& formImageElements() const;
    53     HTMLElement* itemInArrayAfter(unsigned& offset, HTMLElement* previousItem) const OVERRIDE;
     52    virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
    5453};
    5554
  • trunk/Source/WebCore/html/HTMLNameCollection.cpp

    r122115 r122518  
    5050}
    5151
    52 Element* HTMLNameCollection::itemAfter(Node* previous) const
     52Element* HTMLNameCollection::itemAfter(unsigned& offsetInArray, Element* previous) const
    5353{
     54    ASSERT_UNUSED(offsetInArray, !offsetInArray);
    5455    ASSERT(previous != base());
    5556
  • trunk/Source/WebCore/html/HTMLNameCollection.h

    r122115 r122518  
    4444    HTMLNameCollection(Document*, CollectionType, const AtomicString& name);
    4545
    46     virtual Element* itemAfter(Node*) const OVERRIDE;
     46    virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
    4747
    4848    AtomicString m_name;
  • trunk/Source/WebCore/html/HTMLPropertiesCollection.cpp

    r122498 r122518  
    5252
    5353HTMLPropertiesCollection::HTMLPropertiesCollection(Node* itemNode)
    54     : HTMLCollectionWithArrayStorage(itemNode, ItemProperties)
     54    : HTMLCollection(itemNode, ItemProperties)
    5555    , m_hasPropertyNameCache(false)
    5656    , m_hasItemRefElements(false)
     
    113113}
    114114
    115 HTMLElement* HTMLPropertiesCollection::itemInArrayAfter(unsigned& offsetInArray, HTMLElement* previousItem) const
     115Element* HTMLPropertiesCollection::itemAfter(unsigned& offsetInArray, Element* previousItem) const
    116116{
    117117    while (offsetInArray < m_itemRefElements.size()) {
    118         if (HTMLElement* next = itemAfter(m_itemRefElements[offsetInArray], previousItem))
     118        if (Element* next = itemAfter(m_itemRefElements[offsetInArray], previousItem))
    119119            return next;
    120120        offsetInArray++;
     
    124124}
    125125
    126 HTMLElement* HTMLPropertiesCollection::itemAfter(HTMLElement* base, HTMLElement* previous) const
     126HTMLElement* HTMLPropertiesCollection::itemAfter(HTMLElement* base, Element* previous) const
    127127{
    128128    Node* current;
     
    139139
    140140    return 0;
    141 }
    142 
    143 unsigned HTMLPropertiesCollection::calcLength() const
    144 {
    145     unsigned length = 0;
    146     updateRefElements();
    147 
    148     for (unsigned i = 0; i < m_itemRefElements.size(); ++i) {
    149         for (HTMLElement* element = itemAfter(m_itemRefElements[i], 0); element; element = itemAfter(m_itemRefElements[i], element))
    150             ++length;
    151     }
    152 
    153     return length;
    154141}
    155142
  • trunk/Source/WebCore/html/HTMLPropertiesCollection.h

    r122353 r122518  
    4141class DOMStringList;
    4242
    43 class HTMLPropertiesCollection : public HTMLCollectionWithArrayStorage {
     43class HTMLPropertiesCollection : public HTMLCollection {
    4444public:
    4545    static PassRefPtr<HTMLPropertiesCollection> create(Node*);
     
    6464    HTMLPropertiesCollection(Node*);
    6565
    66     virtual unsigned calcLength() const OVERRIDE;
    67 
    6866    Node* findRefElements(Node* previous) const;
    6967
    70     void cacheFirstItem() const;
    71     virtual HTMLElement* itemInArrayAfter(unsigned& offsetInArray, HTMLElement* previousItemInSameArrayElement) const OVERRIDE;
    72     HTMLElement* itemAfter(HTMLElement* base, HTMLElement* previous) const;
     68    virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
     69    HTMLElement* itemAfter(HTMLElement* base, Element* previous) const;
    7370
    7471    void updateNameCache() const;
  • trunk/Source/WebCore/html/HTMLTableRowsCollection.cpp

    r122115 r122518  
    163163}
    164164
    165 Element* HTMLTableRowsCollection::itemAfter(Node* previous) const
     165Element* HTMLTableRowsCollection::itemAfter(unsigned& offsetInArray, Element* previous) const
    166166{
     167    ASSERT_UNUSED(offsetInArray, !offsetInArray);
    167168    ASSERT(!previous || (previous->isHTMLElement() && toHTMLElement(previous)->hasLocalName(trTag)));
    168169    return rowAfter(static_cast<HTMLTableElement*>(base()), static_cast<HTMLTableRowElement*>(previous));
  • trunk/Source/WebCore/html/HTMLTableRowsCollection.h

    r122115 r122518  
    4747    HTMLTableRowsCollection(Element*);
    4848
    49     virtual Element* itemAfter(Node*) const OVERRIDE;
     49    virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
    5050};
    5151
Note: See TracChangeset for help on using the changeset viewer.