Changeset 127438 in webkit


Ignore:
Timestamp:
Sep 3, 2012 7:19:26 PM (12 years ago)
Author:
kling@webkit.org
Message:

Share immutable ElementAttributeData between elements with identical attributes.
<http://webkit.org/b/94990>

Reviewed by Antti Koivisto.

Keep a cache of ElementAttributeData objects for a given set of attributes and reuse
them in elements with identical attribute maps. ElementAttributeData is made ref-counted
to facilitate this. A copy-on-write mechanism is already in place, since mutating call
sites have to go via Element::mutableAttributeData().

The cache is held by Document and cleared in Document::finishedParsing() since the vast
majority of immutable ElementAttributeData will be constructed during parsing.

On the HTML5 spec at <http://whatwg.org/c/>, we get a cache hit rate of nearly 80%,
translating into a 3.5MB reduction in memory use.

  • dom/Document.cpp:

(WebCore::Document::finishedParsing):
(ImmutableAttributeDataCacheKey):
(WebCore::ImmutableAttributeDataCacheKey::ImmutableAttributeDataCacheKey):
(WebCore::ImmutableAttributeDataCacheKey::operator!=):
(WebCore::ImmutableAttributeDataCacheKey::hash):
(ImmutableAttributeDataCacheEntry):
(WebCore::Document::cachedImmutableAttributeData):

  • dom/Document.h:
  • dom/Element.cpp:

(WebCore::Element::parserSetAttributes):

  • dom/Element.h:
  • dom/ElementAttributeData.cpp:

(WebCore::ElementAttributeData::createImmutable):
(WebCore::ElementAttributeData::ElementAttributeData):

  • dom/ElementAttributeData.h:

(WebCore::ElementAttributeData::create):
(ElementAttributeData):
(WebCore::ElementAttributeData::makeMutable):

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r127437 r127438  
     12012-09-03  Andreas Kling  <kling@webkit.org>
     2
     3        Share immutable ElementAttributeData between elements with identical attributes.
     4        <http://webkit.org/b/94990>
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Keep a cache of ElementAttributeData objects for a given set of attributes and reuse
     9        them in elements with identical attribute maps. ElementAttributeData is made ref-counted
     10        to facilitate this. A copy-on-write mechanism is already in place, since mutating call
     11        sites have to go via Element::mutableAttributeData().
     12
     13        The cache is held by Document and cleared in Document::finishedParsing() since the vast
     14        majority of immutable ElementAttributeData will be constructed during parsing.
     15
     16        On the HTML5 spec at <http://whatwg.org/c/>, we get a cache hit rate of nearly 80%,
     17        translating into a 3.5MB reduction in memory use.
     18
     19        * dom/Document.cpp:
     20        (WebCore::Document::finishedParsing):
     21        (ImmutableAttributeDataCacheKey):
     22        (WebCore::ImmutableAttributeDataCacheKey::ImmutableAttributeDataCacheKey):
     23        (WebCore::ImmutableAttributeDataCacheKey::operator!=):
     24        (WebCore::ImmutableAttributeDataCacheKey::hash):
     25        (ImmutableAttributeDataCacheEntry):
     26        (WebCore::Document::cachedImmutableAttributeData):
     27        * dom/Document.h:
     28        * dom/Element.cpp:
     29        (WebCore::Element::parserSetAttributes):
     30        * dom/Element.h:
     31        * dom/ElementAttributeData.cpp:
     32        (WebCore::ElementAttributeData::createImmutable):
     33        (WebCore::ElementAttributeData::ElementAttributeData):
     34        * dom/ElementAttributeData.h:
     35        (WebCore::ElementAttributeData::create):
     36        (ElementAttributeData):
     37        (WebCore::ElementAttributeData::makeMutable):
     38
    1392012-09-03  Peter Wang  <peter.wang@torchmobile.com.cn>
    240
  • trunk/Source/WebCore/dom/Document.cpp

    r127421 r127438  
    48874887        InspectorInstrumentation::domContentLoadedEventFired(f.get());
    48884888    }
     4889
     4890    // The ElementAttributeData sharing cache is only used during parsing since
     4891    // that's when the majority of immutable attribute data will be created.
     4892    m_immutableAttributeDataCache.clear();
    48894893}
    48904894
     
    61736177#endif
    61746178
     6179class ImmutableAttributeDataCacheKey {
     6180public:
     6181    ImmutableAttributeDataCacheKey()
     6182        : m_localName(0)
     6183        , m_attributes(0)
     6184        , m_attributeCount(0)
     6185    { }
     6186
     6187    ImmutableAttributeDataCacheKey(const AtomicString& localName, const Attribute* attributes, unsigned attributeCount)
     6188        : m_localName(localName.impl())
     6189        , m_attributes(attributes)
     6190        , m_attributeCount(attributeCount)
     6191    { }
     6192
     6193    bool operator!=(const ImmutableAttributeDataCacheKey& other) const
     6194    {
     6195        if (m_localName != other.m_localName)
     6196            return true;
     6197        if (m_attributeCount != other.m_attributeCount)
     6198            return true;
     6199        return memcmp(m_attributes, other.m_attributes, sizeof(Attribute) * m_attributeCount);
     6200    }
     6201
     6202    unsigned hash() const
     6203    {
     6204        unsigned attributeHash = StringHasher::hashMemory(m_attributes, m_attributeCount * sizeof(Attribute));
     6205        return WTF::intHash((static_cast<uint64_t>(m_localName->existingHash()) << 32 | attributeHash));
     6206    }
     6207
     6208private:
     6209    AtomicStringImpl* m_localName;
     6210    const Attribute* m_attributes;
     6211    unsigned m_attributeCount;
     6212};
     6213
     6214struct ImmutableAttributeDataCacheEntry {
     6215    ImmutableAttributeDataCacheKey key;
     6216    RefPtr<ElementAttributeData> value;
     6217};
     6218
     6219PassRefPtr<ElementAttributeData> Document::cachedImmutableAttributeData(const Element* element, const Vector<Attribute>& attributes)
     6220{
     6221    ASSERT(!attributes.isEmpty());
     6222
     6223    ImmutableAttributeDataCacheKey cacheKey(element->localName(), attributes.data(), attributes.size());
     6224    unsigned cacheHash = cacheKey.hash();
     6225
     6226    ImmutableAttributeDataCache::iterator cacheIterator = m_immutableAttributeDataCache.add(cacheHash, nullptr).iterator;
     6227    if (cacheIterator->second && cacheIterator->second->key != cacheKey)
     6228        cacheHash = 0;
     6229
     6230    RefPtr<ElementAttributeData> attributeData;
     6231    if (cacheHash && cacheIterator->second)
     6232        attributeData = cacheIterator->second->value;
     6233    else
     6234        attributeData = ElementAttributeData::createImmutable(attributes);
     6235
     6236    if (!cacheHash || cacheIterator->second)
     6237        return attributeData.release();
     6238
     6239    OwnPtr<ImmutableAttributeDataCacheEntry> newEntry = adoptPtr(new ImmutableAttributeDataCacheEntry);
     6240    newEntry->key = ImmutableAttributeDataCacheKey(element->localName(), const_cast<const ElementAttributeData*>(attributeData.get())->attributeItem(0), attributeData->length());
     6241    newEntry->value = attributeData;
     6242
     6243    cacheIterator->second = newEntry.release();
     6244
     6245    return attributeData.release();
     6246}
     6247
    61756248} // namespace WebCore
  • trunk/Source/WebCore/dom/Document.h

    r127228 r127438  
    8484class EditingText;
    8585class Element;
     86class ElementAttributeData;
    8687class EntityReference;
    8788class Event;
     
    207208const int numNodeListInvalidationTypes = InvalidateOnAnyAttrChange + 1;
    208209
     210struct ImmutableAttributeDataCacheEntry;
     211typedef HashMap<unsigned, OwnPtr<ImmutableAttributeDataCacheEntry>, AlreadyHashed> ImmutableAttributeDataCache;
     212
    209213class Document : public ContainerNode, public TreeScope, public ScriptExecutionContext {
    210214public:
     
    11841188    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
    11851189
     1190    PassRefPtr<ElementAttributeData> cachedImmutableAttributeData(const Element*, const Vector<Attribute>&);
     1191
    11861192protected:
    11871193    Document(Frame*, const KURL&, bool isXHTML, bool isHTML);
     
    15691575#endif
    15701576
     1577    ImmutableAttributeDataCache m_immutableAttributeDataCache;
     1578
    15711579#ifndef NDEBUG
    15721580    bool m_didDispatchViewportPropertiesChanged;
  • trunk/Source/WebCore/dom/Element.cpp

    r127228 r127438  
    824824    }
    825825
    826     m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
     826    // When the document is in parsing state, we cache immutable ElementAttributeData objects with the
     827    // input attribute vector as key. (This cache is held by Document.)
     828    if (!document() || !document()->parsing())
     829        m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
     830    else if (!isHTMLElement()) {
     831        // FIXME: Support attribute data sharing for non-HTML elements.
     832        m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
     833    } else
     834        m_attributeData = document()->cachedImmutableAttributeData(this, filteredAttributes);
    827835
    828836    // Iterate over the set of attributes we already have on the stack in case
  • trunk/Source/WebCore/dom/Element.h

    r127228 r127438  
    520520    ElementRareData* ensureElementRareData();
    521521
    522     OwnPtr<ElementAttributeData> m_attributeData;
     522    RefPtr<ElementAttributeData> m_attributeData;
    523523};
    524524   
  • trunk/Source/WebCore/dom/ElementAttributeData.cpp

    r127375 r127438  
    4040}
    4141
    42 PassOwnPtr<ElementAttributeData> ElementAttributeData::createImmutable(const Vector<Attribute>& attributes)
     42PassRefPtr<ElementAttributeData> ElementAttributeData::createImmutable(const Vector<Attribute>& attributes)
    4343{
    4444    void* slot = WTF::fastMalloc(immutableElementAttributeDataSize(attributes.size()));
    45     return adoptPtr(new (slot) ElementAttributeData(attributes));
     45    return adoptRef(new (slot) ElementAttributeData(attributes));
    4646}
    4747
     
    6363
    6464ElementAttributeData::ElementAttributeData(const ElementAttributeData& other)
    65     : m_inlineStyleDecl(other.m_inlineStyleDecl)
     65    : RefCounted<ElementAttributeData>()
     66    , m_isMutable(true)
     67    , m_arraySize(0)
     68    , m_inlineStyleDecl(other.m_inlineStyleDecl)
    6669    , m_attributeStyle(other.m_attributeStyle)
    6770    , m_classNames(other.m_classNames)
    6871    , m_idForStyleResolution(other.m_idForStyleResolution)
    69     , m_isMutable(true)
    70     , m_arraySize(0)
    7172    , m_mutableAttributeVector(new Vector<Attribute, 4>)
    7273{
    7374    // This copy constructor should only be used by makeMutable() to go from immutable to mutable.
    7475    ASSERT(!other.m_isMutable);
     76
     77    // An immutable ElementAttributeData should never have a mutable inline StylePropertySet attached.
     78    ASSERT(!other.m_inlineStyleDecl || !other.m_inlineStyleDecl->isMutable());
    7579
    7680    const Attribute* otherBuffer = reinterpret_cast<const Attribute*>(&other.m_attributes);
  • trunk/Source/WebCore/dom/ElementAttributeData.h

    r127126 r127438  
    4040enum SynchronizationOfLazyAttribute { NotInSynchronizationOfLazyAttribute, InSynchronizationOfLazyAttribute };
    4141
    42 class ElementAttributeData {
     42class ElementAttributeData : public RefCounted<ElementAttributeData> {
    4343    WTF_MAKE_FAST_ALLOCATED;
    4444public:
    45     static PassOwnPtr<ElementAttributeData> create() { return adoptPtr(new ElementAttributeData); }
    46     static PassOwnPtr<ElementAttributeData> createImmutable(const Vector<Attribute>&);
     45    static PassRefPtr<ElementAttributeData> create() { return adoptRef(new ElementAttributeData); }
     46    static PassRefPtr<ElementAttributeData> createImmutable(const Vector<Attribute>&);
    4747    ~ElementAttributeData();
    4848
     
    111111
    112112    bool isMutable() const { return m_isMutable; }
    113     PassOwnPtr<ElementAttributeData> makeMutable() const { return adoptPtr(new ElementAttributeData(*this)); }
     113    PassRefPtr<ElementAttributeData> makeMutable() const { return adoptRef(new ElementAttributeData(*this)); }
     114
     115    unsigned m_isMutable : 1;
     116    unsigned m_arraySize : 31;
    114117
    115118    mutable RefPtr<StylePropertySet> m_inlineStyleDecl;
     
    117120    mutable SpaceSplitString m_classNames;
    118121    mutable AtomicString m_idForStyleResolution;
    119 
    120     unsigned m_isMutable : 1;
    121     unsigned m_arraySize : 31;
    122122
    123123    union {
Note: See TracChangeset for help on using the changeset viewer.