Source/WebCore/ChangeLog

 12012-03-09 Antti Koivisto <antti@apple.com>
 2
 3 Presentation attribute cache
 4 https://bugs.webkit.org/show_bug.cgi?id=80707
 5
 6 It is common for the same presentation attribute values repeat. We should introduce a cache that uses
 7 presentation attribute names and values as key. This will help to avoid repeated parsing of the
 8 same attribute values, reduce memory consumption and speed up the style resolve.
 9
 10 This patch introduces a simple and small (128 entries) global cache. In general web browsing it seems
 11 to give sharing rate of >75% (an average presentation attribute property set is shared between >4 elements).
 12
 13 * dom/StyledElement.cpp:
 14 (WebCore::PresentationAttributeCacheKey::PresentationAttributeCacheKey):
 15 (PresentationAttributeCacheKey):
 16 (WebCore):
 17 (WebCore::operator!=):
 18 (PresentationAttributeCacheEntry):
 19 (WebCore::presentationAttributeCache):
 20 (WebCore::attributeNameSort):
 21 (WebCore::StyledElement::makePresentationAttributeCacheKey):
 22 (WebCore::computePresentationAttributeCacheHash):
 23 (WebCore::StyledElement::updateAttributeStyle):
 24 * dom/StyledElement.h:
 25 (WebCore):
 26 (StyledElement):
 27
1282012-03-09 Nate Chapin <japhet@chromium.org>
229
330 CachedRawResource breaks when trying to load
110303

Source/WebCore/dom/StyledElement.cpp

@@namespace WebCore {
4646
4747using namespace HTMLNames;
4848
 49struct PresentationAttributeCacheKey {
 50 PresentationAttributeCacheKey() : tagName(0) { }
 51 AtomicStringImpl* tagName;
 52 // Only the values need refcounting.
 53 Vector<pair<AtomicStringImpl*, AtomicString>, 3> attributesAndValues;
 54};
 55
 56struct PresentationAttributeCacheEntry {
 57 PresentationAttributeCacheKey key;
 58 RefPtr<StylePropertySet> value;
 59};
 60
 61typedef HashMap<unsigned, OwnPtr<PresentationAttributeCacheEntry>, AlreadyHashed> PresentationAttributeCache;
 62
 63static bool operator!=(const PresentationAttributeCacheKey& a, const PresentationAttributeCacheKey& b)
 64{
 65 if (a.tagName != b.tagName)
 66 return true;
 67 return a.attributesAndValues != b.attributesAndValues;
 68}
 69
 70static PresentationAttributeCache& presentationAttributeCache()
 71{
 72 static PresentationAttributeCache* cache = new PresentationAttributeCache();
 73 return *cache;
 74}
 75
4976void StyledElement::updateStyleAttribute() const
5077{
5178 ASSERT(!isStyleAttributeValid());

@@void StyledElement::addSubresourceAttrib
157184 inlineStyle->addSubresourceStyleURLs(urls, document()->elementSheet());
158185}
159186
160 void StyledElement::updateAttributeStyle()
 187static inline bool attributeNameSort(const pair<AtomicStringImpl*, AtomicString>& p1, const pair<AtomicStringImpl*, AtomicString>& p2)
161188{
162  RefPtr<StylePropertySet> style = StylePropertySet::create();
163  for (unsigned i = 0; i < attributeCount(); ++i) {
 189 // Sort based on the attribute name pointers. It doesn't matter what the order is as long as it is always the same.
 190 return p1.first < p2.first;
 191}
 192
 193void StyledElement::makePresentationAttributeCacheKey(PresentationAttributeCacheKey& result) const
 194{
 195 // FIXME: Enable for SVG.
 196 if (namespaceURI() != xhtmlNamespaceURI)
 197 return;
 198 unsigned size = attributeCount();
 199 for (unsigned i = 0; i < size; ++i) {
164200 Attribute* attribute = attributeItem(i);
165  collectStyleForAttribute(attribute, style.get());
 201 if (!isPresentationAttribute(attribute->name()))
 202 continue;
 203 if (!attribute->namespaceURI().isNull())
 204 return;
 205 // FIXME: Background URL may depend on the base URL and can't be shared. Disallow caching.
 206 if (attribute->name() == backgroundAttr)
 207 return;
 208 result.attributesAndValues.append(make_pair(attribute->localName().impl(), attribute->value()));
 209 }
 210 if (result.attributesAndValues.isEmpty())
 211 return;
 212 // Attribute order doesn't matter. Sort for easy equality comparison.
 213 std::sort(result.attributesAndValues.begin(), result.attributesAndValues.end(), attributeNameSort);
 214 // The cache key is non-null when the tagName is set.
 215 result.tagName = localName().impl();
 216}
 217
 218static unsigned computePresentationAttributeCacheHash(const PresentationAttributeCacheKey& key)
 219{
 220 if (!key.tagName)
 221 return 0;
 222 ASSERT(key.attributesAndValues.size());
 223 unsigned attributeHash = StringHasher::hashMemory(key.attributesAndValues.data(), key.attributesAndValues.size() * sizeof(key.attributesAndValues[0]));
 224 return WTF::intHash((static_cast<uint64_t>(key.tagName->existingHash()) << 32 | attributeHash));
 225}
 226
 227void StyledElement::updateAttributeStyle()
 228{
 229 PresentationAttributeCacheKey cacheKey;
 230 makePresentationAttributeCacheKey(cacheKey);
 231
 232 unsigned cacheHash = computePresentationAttributeCacheHash(cacheKey);
 233
 234 PresentationAttributeCache::iterator cacheIterator;
 235 if (cacheHash) {
 236 cacheIterator = presentationAttributeCache().add(cacheHash, nullptr).first;
 237 if (cacheIterator->second && cacheIterator->second->key != cacheKey)
 238 cacheHash = 0;
 239 }
 240
 241 RefPtr<StylePropertySet> style;
 242 if (cacheHash && cacheIterator->second)
 243 style = cacheIterator->second->value;
 244 else {
 245 style = StylePropertySet::create();
 246 unsigned size = attributeCount();
 247 for (unsigned i = 0; i < size; ++i) {
 248 Attribute* attribute = attributeItem(i);
 249 collectStyleForAttribute(attribute, style.get());
 250 }
166251 }
167252 clearAttributeStyleDirty();
168253

@@void StyledElement::updateAttributeStyle
170255 attributeData()->setAttributeStyle(0);
171256 else {
172257 style->shrinkToFit();
173  attributeData()->setAttributeStyle(style.release());
 258 attributeData()->setAttributeStyle(style);
174259 }
 260
 261 if (!cacheHash || cacheIterator->second)
 262 return;
 263
 264 OwnPtr<PresentationAttributeCacheEntry> newEntry = adoptPtr(new PresentationAttributeCacheEntry);
 265 newEntry->key = cacheKey;
 266 newEntry->value = style.release();
 267
 268 static const int presentationAttributeCacheMaximumSize = 128;
 269 if (presentationAttributeCache().size() > presentationAttributeCacheMaximumSize) {
 270 // Start building from scratch if the cache ever gets big.
 271 presentationAttributeCache().clear();
 272 presentationAttributeCache().set(cacheHash, newEntry.release());
 273 } else
 274 cacheIterator->second = newEntry.release();
175275}
176276
177277void StyledElement::addPropertyToAttributeStyle(StylePropertySet* style, int propertyID, int identifier)
110298

Source/WebCore/dom/StyledElement.h

3131namespace WebCore {
3232
3333class Attribute;
 34struct PresentationAttributeCacheKey;
3435
3536class StyledElement : public Element {
3637public:

@@private:
8283 virtual void updateStyleAttribute() const;
8384 void inlineStyleChanged();
8485
 86 void makePresentationAttributeCacheKey(PresentationAttributeCacheKey&) const;
8587 void updateAttributeStyle();
8688
8789 void destroyInlineStyle()
110298