- Revision
- 135421
- Author
- akl...@apple.com
- Date
- 2012-11-21 11:05:17 -0800 (Wed, 21 Nov 2012)
Log Message
Make it possible for elements with different tag names to share attribute data.
<http://webkit.org/b/102845>
Reviewed by Antti Koivisto.
Allow all elements to share ElementAttributeData with one another. This means that the elements
in this hypothetical markup will all point to the same attribute data:
<div class="foo">
<span class="foo">
<hr class="foo"/>
</span>
</div>
This optimization happens at the expense of an old one. We no longer share attribute data
between elements that have presentation attributes, since they map to different CSS properties
depending on what tag they're attached to. These are mostly used in ye olde web 1.0 content
though, and we should prefer optimizing in favor of modern markup. The global cache for
presentation attribute style in StyledElement.cpp still prevents redundant parsing.
On the upside, excluding elements with presentation attributes from the data cache means that
we can move one pointer (m_presentationAttributeStyle) from ImmutableElementAttributeData
to MutableElementAttributeData.
800kB progression on Membuster3.
* dom/Document.h:
* dom/Document.cpp:
(WebCore::ImmutableAttributeDataCacheKey::ImmutableAttributeDataCacheKey):
(WebCore::ImmutableAttributeDataCacheKey::operator!=):
(WebCore::ImmutableAttributeDataCacheKey::hash):
(ImmutableAttributeDataCacheKey):
(WebCore::Document::cachedImmutableAttributeData):
* dom/Element.cpp:
(WebCore::Element::parserSetAttributes):
Don't use the element's tag name in the key for the immutable attribute data cache.
(WebCore::Element::cloneAttributesFromElement):
Prevent cloneNode() from converting mutable attribute data to immutable if it has
presentation attributes.
* dom/ElementAttributeData.cpp:
(WebCore::ImmutableElementAttributeData::ImmutableElementAttributeData):
Add an assertion that mutable-to-immutable conversion never happens with presentation
attribute style present.
(WebCore::ElementAttributeData::ElementAttributeData):
(WebCore::MutableElementAttributeData::MutableElementAttributeData):
(WebCore::ElementAttributeData::reportMemoryUsage):
* dom/ElementAttributeData.h:
(ElementAttributeData):
(MutableElementAttributeData):
(WebCore::ElementAttributeData::presentationAttributeStyle):
(WebCore):
(WebCore::ElementAttributeData::setPresentationAttributeStyle):
Move the RefPtr<StylePropertySet> that holds presentation attribute-derived style
from the common ElementAttributeData base class to MutableElementAttributeData.
* dom/StyledElement.cpp:
(WebCore::StyledElement::attributeChanged):
Always dirty the presentation attribute style when a presentation attribute changes.
(WebCore::StyledElement::rebuildPresentationAttributeStyle):
Force promotion to mutable attribute data when it turns out that we need to hang a
StylePropertySet with the presentation attribute style off of it.
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (135420 => 135421)
--- trunk/Source/WebCore/ChangeLog 2012-11-21 18:54:26 UTC (rev 135420)
+++ trunk/Source/WebCore/ChangeLog 2012-11-21 19:05:17 UTC (rev 135421)
@@ -1,3 +1,77 @@
+2012-11-21 Andreas Kling <akl...@apple.com>
+
+ Make it possible for elements with different tag names to share attribute data.
+ <http://webkit.org/b/102845>
+
+ Reviewed by Antti Koivisto.
+
+ Allow all elements to share ElementAttributeData with one another. This means that the elements
+ in this hypothetical markup will all point to the same attribute data:
+
+ <div class="foo">
+ <span class="foo">
+ <hr class="foo"/>
+ </span>
+ </div>
+
+ This optimization happens at the expense of an old one. We no longer share attribute data
+ between elements that have presentation attributes, since they map to different CSS properties
+ depending on what tag they're attached to. These are mostly used in ye olde web 1.0 content
+ though, and we should prefer optimizing in favor of modern markup. The global cache for
+ presentation attribute style in StyledElement.cpp still prevents redundant parsing.
+
+ On the upside, excluding elements with presentation attributes from the data cache means that
+ we can move one pointer (m_presentationAttributeStyle) from ImmutableElementAttributeData
+ to MutableElementAttributeData.
+
+ 800kB progression on Membuster3.
+
+ * dom/Document.h:
+ * dom/Document.cpp:
+ (WebCore::ImmutableAttributeDataCacheKey::ImmutableAttributeDataCacheKey):
+ (WebCore::ImmutableAttributeDataCacheKey::operator!=):
+ (WebCore::ImmutableAttributeDataCacheKey::hash):
+ (ImmutableAttributeDataCacheKey):
+ (WebCore::Document::cachedImmutableAttributeData):
+ * dom/Element.cpp:
+ (WebCore::Element::parserSetAttributes):
+
+ Don't use the element's tag name in the key for the immutable attribute data cache.
+
+ (WebCore::Element::cloneAttributesFromElement):
+
+ Prevent cloneNode() from converting mutable attribute data to immutable if it has
+ presentation attributes.
+
+ * dom/ElementAttributeData.cpp:
+ (WebCore::ImmutableElementAttributeData::ImmutableElementAttributeData):
+
+ Add an assertion that mutable-to-immutable conversion never happens with presentation
+ attribute style present.
+
+ (WebCore::ElementAttributeData::ElementAttributeData):
+ (WebCore::MutableElementAttributeData::MutableElementAttributeData):
+ (WebCore::ElementAttributeData::reportMemoryUsage):
+ * dom/ElementAttributeData.h:
+ (ElementAttributeData):
+ (MutableElementAttributeData):
+ (WebCore::ElementAttributeData::presentationAttributeStyle):
+ (WebCore):
+ (WebCore::ElementAttributeData::setPresentationAttributeStyle):
+
+ Move the RefPtr<StylePropertySet> that holds presentation attribute-derived style
+ from the common ElementAttributeData base class to MutableElementAttributeData.
+
+ * dom/StyledElement.cpp:
+ (WebCore::StyledElement::attributeChanged):
+
+ Always dirty the presentation attribute style when a presentation attribute changes.
+
+ (WebCore::StyledElement::rebuildPresentationAttributeStyle):
+
+ Force promotion to mutable attribute data when it turns out that we need to hang a
+ StylePropertySet with the presentation attribute style off of it.
+
2012-11-21 Antti Koivisto <an...@apple.com>
Replace NodeRendererFactory class with a function
Modified: trunk/Source/WebCore/dom/Document.cpp (135420 => 135421)
--- trunk/Source/WebCore/dom/Document.cpp 2012-11-21 18:54:26 UTC (rev 135420)
+++ trunk/Source/WebCore/dom/Document.cpp 2012-11-21 19:05:17 UTC (rev 135421)
@@ -5913,16 +5913,13 @@
class ImmutableAttributeDataCacheKey {
public:
- ImmutableAttributeDataCacheKey(const QualifiedName& tagName, const Attribute* attributes, unsigned attributeCount)
- : m_tagQName(tagName)
- , m_attributes(attributes)
+ ImmutableAttributeDataCacheKey(const Attribute* attributes, unsigned attributeCount)
+ : m_attributes(attributes)
, m_attributeCount(attributeCount)
{ }
bool operator!=(const ImmutableAttributeDataCacheKey& other) const
{
- if (m_tagQName != other.m_tagQName)
- return true;
if (m_attributeCount != other.m_attributeCount)
return true;
return memcmp(m_attributes, other.m_attributes, sizeof(Attribute) * m_attributeCount);
@@ -5930,12 +5927,10 @@
unsigned hash() const
{
- unsigned attributeHash = StringHasher::hashMemory(m_attributes, m_attributeCount * sizeof(Attribute));
- return WTF::pairIntHash(m_tagQName.localName().impl()->existingHash(), attributeHash);
+ return StringHasher::hashMemory(m_attributes, m_attributeCount * sizeof(Attribute));
}
private:
- QualifiedName m_tagQName;
const Attribute* m_attributes;
unsigned m_attributeCount;
};
@@ -5950,11 +5945,11 @@
RefPtr<ElementAttributeData> value;
};
-PassRefPtr<ElementAttributeData> Document::cachedImmutableAttributeData(const Element* element, const Vector<Attribute>& attributes)
+PassRefPtr<ElementAttributeData> Document::cachedImmutableAttributeData(const Vector<Attribute>& attributes)
{
ASSERT(!attributes.isEmpty());
- ImmutableAttributeDataCacheKey cacheKey(element->tagQName(), attributes.data(), attributes.size());
+ ImmutableAttributeDataCacheKey cacheKey(attributes.data(), attributes.size());
unsigned cacheHash = cacheKey.hash();
ImmutableAttributeDataCache::iterator cacheIterator = m_immutableAttributeDataCache.add(cacheHash, nullptr).iterator;
@@ -5970,7 +5965,7 @@
if (!cacheHash || cacheIterator->value)
return attributeData.release();
- cacheIterator->value = adoptPtr(new ImmutableAttributeDataCacheEntry(ImmutableAttributeDataCacheKey(element->tagQName(), attributeData->immutableAttributeArray(), attributeData->length()), attributeData));
+ cacheIterator->value = adoptPtr(new ImmutableAttributeDataCacheEntry(ImmutableAttributeDataCacheKey(attributeData->immutableAttributeArray(), attributeData->length()), attributeData));
return attributeData.release();
}
Modified: trunk/Source/WebCore/dom/Document.h (135420 => 135421)
--- trunk/Source/WebCore/dom/Document.h 2012-11-21 18:54:26 UTC (rev 135420)
+++ trunk/Source/WebCore/dom/Document.h 2012-11-21 19:05:17 UTC (rev 135421)
@@ -1156,7 +1156,7 @@
virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
- PassRefPtr<ElementAttributeData> cachedImmutableAttributeData(const Element*, const Vector<Attribute>&);
+ PassRefPtr<ElementAttributeData> cachedImmutableAttributeData(const Vector<Attribute>&);
void didRemoveAllPendingStylesheet();
void setNeedsNotifyRemoveAllPendingStylesheet() { m_needsNotifyRemoveAllPendingStylesheet = true; }
Modified: trunk/Source/WebCore/dom/Element.cpp (135420 => 135421)
--- trunk/Source/WebCore/dom/Element.cpp 2012-11-21 18:54:26 UTC (rev 135420)
+++ trunk/Source/WebCore/dom/Element.cpp 2012-11-21 19:05:17 UTC (rev 135421)
@@ -1022,11 +1022,11 @@
}
// When the document is in parsing state, we cache immutable ElementAttributeData objects with the
- // input attribute vector (and the tag name) as key. (This cache is held by Document.)
+ // input attribute vector as key. (This cache is held by Document.)
if (!document() || !document()->parsing())
m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
else
- m_attributeData = document()->cachedImmutableAttributeData(this, filteredAttributes);
+ m_attributeData = document()->cachedImmutableAttributeData(filteredAttributes);
// Iterate over the set of attributes we already have on the stack in case
// attributeChanged mutates m_attributeData.
@@ -2563,8 +2563,10 @@
updateName(oldName, newName);
// If 'other' has a mutable ElementAttributeData, convert it to an immutable one so we can share it between both elements.
- // We can only do this if there is no CSSOM wrapper for other's inline style (the isMutable() check.)
- if (other.m_attributeData->isMutable() && (!other.m_attributeData->inlineStyle() || !other.m_attributeData->inlineStyle()->isMutable()))
+ // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
+ if (other.m_attributeData->isMutable()
+ && !other.m_attributeData->presentationAttributeStyle()
+ && (!other.m_attributeData->inlineStyle() || !other.m_attributeData->inlineStyle()->hasCSSOMWrapper()))
const_cast<Element&>(other).m_attributeData = other.m_attributeData->makeImmutableCopy();
if (!other.m_attributeData->isMutable())
Modified: trunk/Source/WebCore/dom/ElementAttributeData.cpp (135420 => 135421)
--- trunk/Source/WebCore/dom/ElementAttributeData.cpp 2012-11-21 18:54:26 UTC (rev 135420)
+++ trunk/Source/WebCore/dom/ElementAttributeData.cpp 2012-11-21 19:05:17 UTC (rev 135421)
@@ -33,7 +33,7 @@
struct SameSizeAsElementAttributeData : public RefCounted<SameSizeAsElementAttributeData> {
unsigned bitfield;
- void* refPtrs[4];
+ void* refPtrs[3];
};
COMPILE_ASSERT(sizeof(ElementAttributeData) == sizeof(ElementAttributeData), element_attribute_data_should_stay_small);
@@ -70,6 +70,8 @@
ImmutableElementAttributeData::ImmutableElementAttributeData(const MutableElementAttributeData& other)
: ElementAttributeData(other, false)
{
+ ASSERT(!other.m_presentationAttributeStyle);
+
if (other.m_inlineStyle) {
ASSERT(!other.m_inlineStyle->isMutable());
m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
@@ -84,7 +86,6 @@
, m_arraySize(isMutable ? 0 : other.length())
, m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
, m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
- , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
, m_classNames(other.m_classNames)
, m_idForStyleResolution(other.m_idForStyleResolution)
{
@@ -93,6 +94,7 @@
MutableElementAttributeData::MutableElementAttributeData(const MutableElementAttributeData& other)
: ElementAttributeData(other, true)
+ , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
, m_attributeVector(other.m_attributeVector)
{
m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->copy() : 0;
@@ -161,11 +163,12 @@
size_t actualSize = m_isMutable ? sizeof(ElementAttributeData) : sizeForImmutableElementAttributeDataWithAttributeCount(m_arraySize);
MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM, actualSize);
info.addMember(m_inlineStyle);
- info.addMember(m_presentationAttributeStyle);
info.addMember(m_classNames);
info.addMember(m_idForStyleResolution);
- if (m_isMutable)
+ if (m_isMutable) {
+ info.addMember(presentationAttributeStyle());
info.addMember(mutableAttributeVector());
+ }
for (unsigned i = 0, len = length(); i < len; i++)
info.addMember(*attributeItem(i));
}
Modified: trunk/Source/WebCore/dom/ElementAttributeData.h (135420 => 135421)
--- trunk/Source/WebCore/dom/ElementAttributeData.h 2012-11-21 18:54:26 UTC (rev 135420)
+++ trunk/Source/WebCore/dom/ElementAttributeData.h 2012-11-21 19:05:17 UTC (rev 135421)
@@ -56,8 +56,8 @@
const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
- const StylePropertySet* presentationAttributeStyle() const { return m_presentationAttributeStyle.get(); }
- void setPresentationAttributeStyle(PassRefPtr<StylePropertySet> style) const { m_presentationAttributeStyle = style; }
+ const StylePropertySet* presentationAttributeStyle() const;
+ void setPresentationAttributeStyle(PassRefPtr<StylePropertySet>) const;
size_t length() const;
bool isEmpty() const { return !length(); }
@@ -107,7 +107,6 @@
mutable unsigned m_styleAttributeIsDirty : 1;
mutable RefPtr<StylePropertySet> m_inlineStyle;
- mutable RefPtr<StylePropertySet> m_presentationAttributeStyle;
mutable SpaceSplitString m_classNames;
mutable AtomicString m_idForStyleResolution;
@@ -143,6 +142,7 @@
MutableElementAttributeData(const ImmutableElementAttributeData&);
MutableElementAttributeData(const MutableElementAttributeData&);
+ mutable RefPtr<StylePropertySet> m_presentationAttributeStyle;
Vector<Attribute, 4> m_attributeVector;
};
@@ -171,6 +171,19 @@
return m_arraySize;
}
+inline const StylePropertySet* ElementAttributeData::presentationAttributeStyle() const
+{
+ if (!m_isMutable)
+ return 0;
+ return static_cast<const MutableElementAttributeData*>(this)->m_presentationAttributeStyle.get();
+}
+
+inline void ElementAttributeData::setPresentationAttributeStyle(PassRefPtr<StylePropertySet> style) const
+{
+ ASSERT(m_isMutable);
+ static_cast<const MutableElementAttributeData*>(this)->m_presentationAttributeStyle = style;
+}
+
inline Attribute* ElementAttributeData::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase)
{
size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase);
Modified: trunk/Source/WebCore/dom/StyledElement.cpp (135420 => 135421)
--- trunk/Source/WebCore/dom/StyledElement.cpp 2012-11-21 18:54:26 UTC (rev 135420)
+++ trunk/Source/WebCore/dom/StyledElement.cpp 2012-11-21 19:05:17 UTC (rev 135421)
@@ -161,9 +161,7 @@
if (name == styleAttr)
styleAttributeChanged(newValue);
else if (isPresentationAttribute(name)) {
- // Avoid dirtying the presentation attribute style if we're using shared attribute data with already generated style.
- if (attributeData()->isMutable() || !attributeData()->m_presentationAttributeStyle)
- attributeData()->m_presentationAttributeStyleIsDirty = true;
+ attributeData()->m_presentationAttributeStyleIsDirty = true;
setNeedsStyleRecalc(InlineStyleChange);
}
@@ -342,9 +340,12 @@
}
}
- attributeData()->m_presentationAttributeStyleIsDirty = false;
- attributeData()->setPresentationAttributeStyle(style->isEmpty() ? 0 : style);
+ // ImmutableElementAttributeData doesn't store presentation attribute style, so make sure we have a MutableElementAttributeData.
+ ElementAttributeData* attributeData = mutableAttributeData();
+ attributeData->m_presentationAttributeStyleIsDirty = false;
+ attributeData->setPresentationAttributeStyle(style->isEmpty() ? 0 : style);
+
if (!cacheHash || cacheIterator->value)
return;