Title: [118809] trunk/Source/WebCore
Revision
118809
Author
[email protected]
Date
2012-05-29 11:19:59 -0700 (Tue, 29 May 2012)

Log Message

Make StylePropertySet a variable-sized object to reduce memory use.
<http://webkit.org/b/87506>

Reviewed by Antti Koivisto.

Make immutable StylePropertySet objects variable-sized and allocate exactly
the space needed to hold the CSSProperty objects passed at construction.
This lets us avoid the memory overhead of Vector<CSSProperty, 4>.

Renamed StylePropertySet::adopt* to create and createImmutable since they no
longer adopt the incoming vector. More cleanup will follow in this area.

This reduces memory usage across the board - the more CSS declarations,
the bigger the benefit. As an example, we save around ~0.5MB on wsj.com.

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::CSSComputedStyleDeclaration::copyPropertiesInSet):
* css/CSSParser.cpp:
(WebCore::CSSParser::createStylePropertySet):
* css/StylePropertySet.cpp:
(WebCore::StylePropertySet::createImmutable):
(WebCore::StylePropertySet::StylePropertySet):
(WebCore::StylePropertySet::~StylePropertySet):
(WebCore::StylePropertySet::copyPropertiesFrom):
(WebCore::StylePropertySet::removeProperty):
(WebCore::StylePropertySet::setProperty):
(WebCore::StylePropertySet::parseDeclaration):
(WebCore::StylePropertySet::addParsedProperties):
(WebCore::StylePropertySet::asText):
(WebCore::StylePropertySet::merge):
(WebCore::StylePropertySet::addSubresourceStyleURLs):
(WebCore::StylePropertySet::removePropertiesInSet):
(WebCore::StylePropertySet::findPropertyWithId):
(WebCore::StylePropertySet::removeEquivalentProperties):
(WebCore::StylePropertySet::copyPropertiesInSet):
(WebCore::StylePropertySet::averageSizeInBytes):
(SameSizeAsStylePropertySet):
(WebCore::StylePropertySet::append):
* css/StylePropertySet.h:
(WebCore::StylePropertySet::create):
(StylePropertySet):
(WebCore::StylePropertySet::propertyAt):
(WebCore::StylePropertySet::propertyCount):
(WebCore::StylePropertySet::isEmpty):
(WebCore::StylePropertySet::array):
* dom/StyledElement.cpp:
(WebCore::StyledElement::updateAttributeStyle):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (118808 => 118809)


--- trunk/Source/WebCore/ChangeLog	2012-05-29 18:15:03 UTC (rev 118808)
+++ trunk/Source/WebCore/ChangeLog	2012-05-29 18:19:59 UTC (rev 118809)
@@ -1,3 +1,53 @@
+2012-05-29  Andreas Kling  <[email protected]>
+
+        Make StylePropertySet a variable-sized object to reduce memory use.
+        <http://webkit.org/b/87506>
+
+        Reviewed by Antti Koivisto.
+
+        Make immutable StylePropertySet objects variable-sized and allocate exactly
+        the space needed to hold the CSSProperty objects passed at construction.
+        This lets us avoid the memory overhead of Vector<CSSProperty, 4>.
+
+        Renamed StylePropertySet::adopt* to create and createImmutable since they no
+        longer adopt the incoming vector. More cleanup will follow in this area.
+
+        This reduces memory usage across the board - the more CSS declarations,
+        the bigger the benefit. As an example, we save around ~0.5MB on wsj.com.
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::CSSComputedStyleDeclaration::copyPropertiesInSet):
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::createStylePropertySet):
+        * css/StylePropertySet.cpp:
+        (WebCore::StylePropertySet::createImmutable):
+        (WebCore::StylePropertySet::StylePropertySet):
+        (WebCore::StylePropertySet::~StylePropertySet):
+        (WebCore::StylePropertySet::copyPropertiesFrom):
+        (WebCore::StylePropertySet::removeProperty):
+        (WebCore::StylePropertySet::setProperty):
+        (WebCore::StylePropertySet::parseDeclaration):
+        (WebCore::StylePropertySet::addParsedProperties):
+        (WebCore::StylePropertySet::asText):
+        (WebCore::StylePropertySet::merge):
+        (WebCore::StylePropertySet::addSubresourceStyleURLs):
+        (WebCore::StylePropertySet::removePropertiesInSet):
+        (WebCore::StylePropertySet::findPropertyWithId):
+        (WebCore::StylePropertySet::removeEquivalentProperties):
+        (WebCore::StylePropertySet::copyPropertiesInSet):
+        (WebCore::StylePropertySet::averageSizeInBytes):
+        (SameSizeAsStylePropertySet):
+        (WebCore::StylePropertySet::append):
+        * css/StylePropertySet.h:
+        (WebCore::StylePropertySet::create):
+        (StylePropertySet):
+        (WebCore::StylePropertySet::propertyAt):
+        (WebCore::StylePropertySet::propertyCount):
+        (WebCore::StylePropertySet::isEmpty):
+        (WebCore::StylePropertySet::array):
+        * dom/StyledElement.cpp:
+        (WebCore::StyledElement::updateAttributeStyle):
+
 2012-05-29  David Hyatt  <[email protected]>
 
         https://bugs.webkit.org/show_bug.cgi?id=87759

Modified: trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp (118808 => 118809)


--- trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp	2012-05-29 18:15:03 UTC (rev 118808)
+++ trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp	2012-05-29 18:19:59 UTC (rev 118809)
@@ -2641,7 +2641,7 @@
         if (value)
             list.append(CSSProperty(set[i], value.release(), false));
     }
-    return StylePropertySet::adoptMutable(list);
+    return StylePropertySet::create(list);
 }
 
 CSSRule* CSSComputedStyleDeclaration::parentRule() const

Modified: trunk/Source/WebCore/css/CSSParser.cpp (118808 => 118809)


--- trunk/Source/WebCore/css/CSSParser.cpp	2012-05-29 18:15:03 UTC (rev 118808)
+++ trunk/Source/WebCore/css/CSSParser.cpp	2012-05-29 18:19:59 UTC (rev 118809)
@@ -1200,7 +1200,7 @@
     if (unusedEntries)
         results.remove(0, unusedEntries);
 
-    return StylePropertySet::adopt(results, m_context.mode);
+    return StylePropertySet::createImmutable(results, m_context.mode);
 }
 
 void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)

Modified: trunk/Source/WebCore/css/StylePropertySet.cpp (118808 => 118809)


--- trunk/Source/WebCore/css/StylePropertySet.cpp	2012-05-29 18:15:03 UTC (rev 118808)
+++ trunk/Source/WebCore/css/StylePropertySet.cpp	2012-05-29 18:19:59 UTC (rev 118809)
@@ -50,31 +50,45 @@
     return propertySetCSSOMWrapperMapInstance;
 }
 
+PassRefPtr<StylePropertySet> StylePropertySet::createImmutable(StylePropertyVector& properties, CSSParserMode cssParserMode)
+{
+    void* slot = WTF::fastMalloc(sizeof(StylePropertySet) - sizeof(void*) + sizeof(CSSProperty) * properties.size());
+    return adoptRef(new (slot) StylePropertySet(properties, cssParserMode, /* makeMutable */ false));
+}
+
 StylePropertySet::StylePropertySet(CSSParserMode cssParserMode)
     : m_cssParserMode(cssParserMode)
     , m_ownsCSSOMWrapper(false)
     , m_isMutable(true)
+    , m_arraySize(0)
+    , m_mutablePropertyVector(new Vector<CSSProperty>)
 {
 }
 
-StylePropertySet::StylePropertySet(StylePropertyVector& properties, CSSParserMode cssParserMode)
+StylePropertySet::StylePropertySet(StylePropertyVector& properties, CSSParserMode cssParserMode, bool makeMutable)
     : m_cssParserMode(cssParserMode)
     , m_ownsCSSOMWrapper(false)
-    , m_isMutable(false)
+    , m_isMutable(makeMutable)
 {
-    m_properties.swap(properties);
-
-    // This shrinkToFit() will be a no-op in the typical case (no duplicate properties were eliminated after parsing.)
-    m_properties.shrinkToFit();
+    if (makeMutable) {
+        m_mutablePropertyVector = new Vector<CSSProperty>;
+        *m_mutablePropertyVector = properties;
+    } else {
+        m_arraySize = properties.size();
+        for (unsigned i = 0; i < m_arraySize; ++i)
+            new (&array()[i]) CSSProperty(properties[i]);
+    }
 }
 
 StylePropertySet::StylePropertySet(const StylePropertySet& o)
     : RefCounted<StylePropertySet>()
-    , m_properties(o.m_properties)
     , m_cssParserMode(o.m_cssParserMode)
     , m_ownsCSSOMWrapper(false)
     , m_isMutable(true)
+    , m_arraySize(0)
+    , m_mutablePropertyVector(new Vector<CSSProperty>)
 {
+    copyPropertiesFrom(o);
 }
 
 StylePropertySet::~StylePropertySet()
@@ -82,6 +96,12 @@
     ASSERT(!m_ownsCSSOMWrapper || propertySetCSSOMWrapperMap().contains(this));
     if (m_ownsCSSOMWrapper)
         propertySetCSSOMWrapperMap().remove(this);
+    if (isMutable())
+        delete m_mutablePropertyVector;
+    else {
+        for (unsigned i = 0; i < m_arraySize; ++i)
+            array()[i].~CSSProperty();
+    }
 }
 
 void StylePropertySet::setCSSParserMode(CSSParserMode cssParserMode)
@@ -93,7 +113,16 @@
 void StylePropertySet::copyPropertiesFrom(const StylePropertySet& other)
 {
     ASSERT(isMutable());
-    m_properties = other.m_properties;
+
+    if (other.isMutable()) {
+        *m_mutablePropertyVector = *other.m_mutablePropertyVector;
+        return;
+    }
+
+    ASSERT(m_mutablePropertyVector->isEmpty());
+    m_mutablePropertyVector->reserveInitialCapacity(other.m_arraySize);
+    for (unsigned i = 0; i < other.m_arraySize; ++i)
+        m_mutablePropertyVector->uncheckedAppend(other.array()[i]);
 }
 
 String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const
@@ -492,7 +521,7 @@
 
     // A more efficient removal strategy would involve marking entries as empty
     // and sweeping them when the vector grows too big.
-    m_properties.remove(foundProperty - m_properties.data());
+    m_mutablePropertyVector->remove(foundProperty - m_mutablePropertyVector->data());
     
     return true;
 }
@@ -554,7 +583,7 @@
 
     RefPtr<CSSValue> value = prpValue;
     for (unsigned i = 0; i < shorthand.length(); ++i)
-        m_properties.append(CSSProperty(shorthand.properties()[i], value, important));
+        append(CSSProperty(shorthand.properties()[i], value, important));
 }
 
 void StylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slot)
@@ -567,7 +596,7 @@
             return;
         }
     }
-    m_properties.append(property);
+    append(property);
 }
 
 bool StylePropertySet::setProperty(CSSPropertyID propertyID, int identifier, bool important)
@@ -581,7 +610,7 @@
 {
     ASSERT(isMutable());
 
-    m_properties.clear();
+    m_mutablePropertyVector->clear();
 
     CSSParserContext context(cssParserMode());
     if (contextStyleSheet) {
@@ -595,7 +624,7 @@
 void StylePropertySet::addParsedProperties(const Vector<CSSProperty>& properties)
 {
     ASSERT(isMutable());
-    m_properties.reserveCapacity(m_properties.size() + properties.size());
+    m_mutablePropertyVector->reserveCapacity(m_mutablePropertyVector->size() + properties.size());
     for (unsigned i = 0; i < properties.size(); ++i)
         addParsedProperty(properties[i]);
 }
@@ -620,9 +649,9 @@
     BitArray<numCSSProperties> shorthandPropertyUsed;
     BitArray<numCSSProperties> shorthandPropertyAppeared;
 
-    unsigned size = m_properties.size();
+    unsigned size = propertyCount();
     for (unsigned n = 0; n < size; ++n) {
-        const CSSProperty& prop = m_properties[n];
+        const CSSProperty& prop = propertyAt(n);
         CSSPropertyID propertyID = prop.id();
         CSSPropertyID shorthandPropertyID = CSSPropertyInvalid;
         CSSPropertyID borderFallbackShorthandProperty = CSSPropertyInvalid;
@@ -833,24 +862,24 @@
 void StylePropertySet::merge(const StylePropertySet* other, bool argOverridesOnConflict)
 {
     ASSERT(isMutable());
-    unsigned size = other->m_properties.size();
+    unsigned size = other->propertyCount();
     for (unsigned n = 0; n < size; ++n) {
-        const CSSProperty& toMerge = other->m_properties[n];
+        const CSSProperty& toMerge = other->propertyAt(n);
         CSSProperty* old = findPropertyWithId(toMerge.id());
         if (old) {
             if (!argOverridesOnConflict && old->value())
                 continue;
             setProperty(toMerge, old);
         } else
-            m_properties.append(toMerge);
+            append(toMerge);
     }
 }
 
 void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, StyleSheetContents* contextStyleSheet) const
 {
-    size_t size = m_properties.size();
-    for (size_t i = 0; i < size; ++i)
-        m_properties[i].value()->addSubresourceStyleURLs(urls, contextStyleSheet);
+    unsigned size = propertyCount();
+    for (unsigned i = 0; i < size; ++i)
+        propertyAt(i).value()->addSubresourceStyleURLs(urls, contextStyleSheet);
 }
 
 // This is the list of properties we want to copy in the copyBlockProperties() function.
@@ -896,7 +925,7 @@
 bool StylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length)
 {
     ASSERT(isMutable());
-    if (m_properties.isEmpty())
+    if (m_mutablePropertyVector->isEmpty())
         return false;
 
     // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless.
@@ -905,11 +934,11 @@
         toRemove.add(set[i]);
 
     StylePropertyVector newProperties;
-    newProperties.reserveInitialCapacity(m_properties.size());
+    newProperties.reserveInitialCapacity(m_mutablePropertyVector->size());
 
-    unsigned size = m_properties.size();
+    unsigned size = m_mutablePropertyVector->size();
     for (unsigned n = 0; n < size; ++n) {
-        const CSSProperty& property = m_properties[n];
+        const CSSProperty& property = m_mutablePropertyVector->at(n);
         // Not quite sure if the isImportant test is needed but it matches the existing behavior.
         if (!property.isImportant()) {
             if (toRemove.contains(property.id()))
@@ -918,16 +947,16 @@
         newProperties.append(property);
     }
 
-    bool changed = newProperties.size() != m_properties.size();
-    m_properties = newProperties;
+    bool changed = newProperties.size() != m_mutablePropertyVector->size();
+    *m_mutablePropertyVector = newProperties;
     return changed;
 }
 
 const CSSProperty* StylePropertySet::findPropertyWithId(CSSPropertyID propertyID) const
 {
-    for (int n = m_properties.size() - 1 ; n >= 0; --n) {
-        if (propertyID == m_properties[n].id())
-            return &m_properties[n];
+    for (int n = propertyCount() - 1 ; n >= 0; --n) {
+        if (propertyID == propertyAt(n).id())
+            return &propertyAt(n);
     }
     return 0;
 }
@@ -935,9 +964,9 @@
 CSSProperty* StylePropertySet::findPropertyWithId(CSSPropertyID propertyID)
 {
     ASSERT(isMutable());
-    for (int n = m_properties.size() - 1 ; n >= 0; --n) {
-        if (propertyID == m_properties[n].id())
-            return &m_properties[n];
+    for (int n = propertyCount() - 1 ; n >= 0; --n) {
+        if (propertyID == propertyAt(n).id())
+            return &propertyAt(n);
     }
     return 0;
 }
@@ -952,9 +981,9 @@
 {
     ASSERT(isMutable());
     Vector<CSSPropertyID> propertiesToRemove;
-    size_t size = m_properties.size();
-    for (size_t i = 0; i < size; ++i) {
-        const CSSProperty& property = m_properties[i];
+    unsigned size = m_mutablePropertyVector->size();
+    for (unsigned i = 0; i < size; ++i) {
+        const CSSProperty& property = m_mutablePropertyVector->at(i);
         if (style->propertyMatches(&property))
             propertiesToRemove.append(property.id());
     }    
@@ -967,9 +996,9 @@
 {
     ASSERT(isMutable());
     Vector<CSSPropertyID> propertiesToRemove;
-    size_t size = m_properties.size();
-    for (size_t i = 0; i < size; ++i) {
-        const CSSProperty& property = m_properties[i];
+    unsigned size = m_mutablePropertyVector->size();
+    for (unsigned i = 0; i < size; ++i) {
+        const CSSProperty& property = m_mutablePropertyVector->at(i);
         if (style->cssPropertyMatches(&property))
             propertiesToRemove.append(property.id());
     }    
@@ -992,7 +1021,7 @@
         if (value)
             list.append(CSSProperty(set[i], value.release(), false));
     }
-    return StylePropertySet::adoptMutable(list);
+    return StylePropertySet::create(list);
 }
 
 CSSStyleDeclaration* StylePropertySet::ensureCSSStyleDeclaration() const
@@ -1031,13 +1060,13 @@
 unsigned StylePropertySet::averageSizeInBytes()
 {
     // Please update this if the storage scheme changes so that this longer reflects the actual size.
-    return sizeof(StylePropertySet);
+    return sizeof(StylePropertySet) + sizeof(CSSProperty) * 2;
 }
 
 // See the function above if you need to update this.
 class SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> {
-    StylePropertyVector properties;
     unsigned bitfield;
+    void* properties;
 };
 COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
 
@@ -1048,4 +1077,10 @@
 }
 #endif
 
+inline void StylePropertySet::append(const CSSProperty& property)
+{
+    ASSERT(isMutable());
+    m_mutablePropertyVector->append(property);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/css/StylePropertySet.h (118808 => 118809)


--- trunk/Source/WebCore/css/StylePropertySet.h	2012-05-29 18:15:03 UTC (rev 118808)
+++ trunk/Source/WebCore/css/StylePropertySet.h	2012-05-29 18:19:59 UTC (rev 118809)
@@ -49,23 +49,17 @@
     {
         return adoptRef(new StylePropertySet(cssParserMode));
     }
-    static PassRefPtr<StylePropertySet> adopt(StylePropertyVector& properties, CSSParserMode cssParserMode)
+    static PassRefPtr<StylePropertySet> create(StylePropertyVector& properties)
     {
-        return adoptRef(new StylePropertySet(properties, cssParserMode));
+        return adoptRef(new StylePropertySet(properties, CSSStrictMode, /* makeMutable */ true));
     }
-    static PassRefPtr<StylePropertySet> adoptMutable(StylePropertyVector& properties)
-    {
-        RefPtr<StylePropertySet> result = adoptRef(new StylePropertySet(properties, CSSStrictMode));
-        result->m_isMutable = true;
-        return result.release();
-    }
+    static PassRefPtr<StylePropertySet> createImmutable(StylePropertyVector&, CSSParserMode);
 
-    unsigned propertyCount() const { return m_properties.size(); }
-    bool isEmpty() const { return m_properties.isEmpty(); }
-    const CSSProperty& propertyAt(unsigned index) const { return m_properties[index]; }
+    unsigned propertyCount() const;
+    bool isEmpty() const;
+    const CSSProperty& propertyAt(unsigned index) const;
+    CSSProperty& propertyAt(unsigned index);
 
-    void shrinkToFit() { m_properties.shrinkToFit(); }
-
     PassRefPtr<CSSValue> getPropertyCSSValue(CSSPropertyID) const;
     String getPropertyValue(CSSPropertyID) const;
     bool propertyIsImportant(CSSPropertyID) const;
@@ -125,7 +119,7 @@
     
 private:
     StylePropertySet(CSSParserMode);
-    StylePropertySet(StylePropertyVector&, CSSParserMode);
+    StylePropertySet(StylePropertyVector&, CSSParserMode, bool makeMutable);
     StylePropertySet(const StylePropertySet&);
 
     void setNeedsStyleRecalc();
@@ -146,15 +140,61 @@
     const CSSProperty* findPropertyWithId(CSSPropertyID) const;
     CSSProperty* findPropertyWithId(CSSPropertyID);
 
-    StylePropertyVector m_properties;
+    void append(const CSSProperty&);
+    CSSProperty* array();
+    const CSSProperty* array() const;
 
     unsigned m_cssParserMode : 2;
     mutable unsigned m_ownsCSSOMWrapper : 1;
     mutable unsigned m_isMutable : 1;
+    unsigned m_arraySize : 28;
+
+    union {
+        Vector<CSSProperty>* m_mutablePropertyVector;
+        void* m_properties;
+    };
     
     friend class PropertySetCSSStyleDeclaration;
 };
 
+inline CSSProperty& StylePropertySet::propertyAt(unsigned index)
+{
+    if (isMutable())
+        return m_mutablePropertyVector->at(index);
+    return array()[index];
+}
+
+inline const CSSProperty& StylePropertySet::propertyAt(unsigned index) const
+{
+    if (isMutable())
+        return m_mutablePropertyVector->at(index);
+    return array()[index];
+}
+
+inline unsigned StylePropertySet::propertyCount() const
+{
+    if (isMutable())
+        return m_mutablePropertyVector->size();
+    return m_arraySize;
+}
+
+inline bool StylePropertySet::isEmpty() const
+{
+    return !propertyCount();
+}
+
+inline CSSProperty* StylePropertySet::array()
+{
+    ASSERT(!isMutable());
+    return reinterpret_cast<CSSProperty*>(&m_properties);
+}
+
+inline const CSSProperty* StylePropertySet::array() const
+{
+    ASSERT(!isMutable());
+    return reinterpret_cast<const CSSProperty*>(&m_properties);
+}
+
 } // namespace WebCore
 
 #endif // StylePropertySet_h

Modified: trunk/Source/WebCore/dom/StyledElement.cpp (118808 => 118809)


--- trunk/Source/WebCore/dom/StyledElement.cpp	2012-05-29 18:15:03 UTC (rev 118808)
+++ trunk/Source/WebCore/dom/StyledElement.cpp	2012-05-29 18:19:59 UTC (rev 118809)
@@ -317,12 +317,7 @@
     }
     clearAttributeStyleDirty();
 
-    if (style->isEmpty())
-        attributeData()->setAttributeStyle(0);
-    else {
-        style->shrinkToFit();
-        attributeData()->setAttributeStyle(style);
-    }
+    attributeData()->setAttributeStyle(style->isEmpty() ? 0 : style);
 
     if (!cacheHash || cacheIterator->second)
         return;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to