Keep ElementAttributeData sharing cache open for a while after document parsing finishes.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 2 Dec 2012 12:03:44 +0000 (12:03 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 2 Dec 2012 12:03:44 +0000 (12:03 +0000)
<http://webkit.org/b/103720>

Reviewed by Antti Koivisto.

Allow web pages that generate content dynamically to benefit more from the ElementAttributeData sharing
cache by keeping it open for 10 seconds after document parsing finishes. This enables elements constructed
from HTML fragments to share attribute data with other identical elements.

Elements created via Document.createElement are still unsupported since we don't know the list of attributes
at the time of construction.

401kB progression on Membuster3.

Document now holds on to a DocumentSharedObjectPool, accessible via Document::sharedObjectPool().
It is non-null during parsing and for some time afterwards, and can be used to implement additional
caches that are not worth holding on to permanently.

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.xcodeproj/project.pbxproj:
* WebCore.vcproj/WebCore.vcproj:

    Add new class DocumentSharedObjectPool.

* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::setParsing):
(WebCore::Document::finishedParsing):
(WebCore::Document::sharedObjectPoolClearTimerFired):
* dom/Document.h:
(WebCore::Document::sharedObjectPool):

    Create DocumentSharedObjectPool when parsing starts, kill it on a 10s timer after parsing finishes.

* dom/DocumentSharedObjectPool.cpp: Added.
(ImmutableElementAttributeDataCacheKey):
(WebCore::ImmutableElementAttributeDataCacheKey::ImmutableElementAttributeDataCacheKey):
(WebCore::ImmutableElementAttributeDataCacheKey::operator!=):
(WebCore::ImmutableElementAttributeDataCacheKey::hash):
(ImmutableElementAttributeDataCacheEntry):
(WebCore::ImmutableElementAttributeDataCacheEntry::ImmutableElementAttributeDataCacheEntry):
(WebCore::DocumentSharedObjectPool::cachedImmutableElementAttributeData):
(WebCore::DocumentSharedObjectPool::DocumentSharedObjectPool):
(WebCore::DocumentSharedObjectPool::~DocumentSharedObjectPool):
* dom/DocumentSharedObjectPool.h: Added.
(DocumentSharedObjectPool):
(WebCore::DocumentSharedObjectPool::create):
* dom/Element.cpp:
(WebCore::Element::parserSetAttributes):

    Moved the ElementAttributeData cache to DocumentSharedObjectPool.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@136334 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/DOMAllInOne.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/DocumentSharedObjectPool.cpp [new file with mode: 0644]
Source/WebCore/dom/DocumentSharedObjectPool.h [new file with mode: 0644]
Source/WebCore/dom/Element.cpp

index 961c5d55938cc480b7e2a85256e0f527320396db..9d10dc43b16b002260de425deab3592434ca0f97 100644 (file)
@@ -1145,6 +1145,7 @@ SET(WebCore_SOURCES
     dom/DocumentFragment.cpp
     dom/DocumentParser.cpp
     dom/DocumentOrderedMap.cpp
+    dom/DocumentSharedObjectPool.cpp
     dom/DocumentStyleSheetCollection.cpp
     dom/DocumentType.cpp
     dom/Element.cpp
index ce77983b7dff1775f638c30d4028ecd11180a8e7..dd75e54026ee680853af560996e4897b5496f2d8 100644 (file)
@@ -1,3 +1,60 @@
+2012-12-02  Andreas Kling  <akling@apple.com>
+
+        Keep ElementAttributeData sharing cache open for a while after document parsing finishes.
+        <http://webkit.org/b/103720>
+
+        Reviewed by Antti Koivisto.
+
+        Allow web pages that generate content dynamically to benefit more from the ElementAttributeData sharing
+        cache by keeping it open for 10 seconds after document parsing finishes. This enables elements constructed
+        from HTML fragments to share attribute data with other identical elements.
+
+        Elements created via Document.createElement are still unsupported since we don't know the list of attributes
+        at the time of construction.
+
+        401kB progression on Membuster3.
+
+        Document now holds on to a DocumentSharedObjectPool, accessible via Document::sharedObjectPool().
+        It is non-null during parsing and for some time afterwards, and can be used to implement additional
+        caches that are not worth holding on to permanently.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.gypi:
+        * WebCore.xcodeproj/project.pbxproj:
+        * WebCore.vcproj/WebCore.vcproj:
+
+            Add new class DocumentSharedObjectPool.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::setParsing):
+        (WebCore::Document::finishedParsing):
+        (WebCore::Document::sharedObjectPoolClearTimerFired):
+        * dom/Document.h:
+        (WebCore::Document::sharedObjectPool):
+
+            Create DocumentSharedObjectPool when parsing starts, kill it on a 10s timer after parsing finishes.
+
+        * dom/DocumentSharedObjectPool.cpp: Added.
+        (ImmutableElementAttributeDataCacheKey):
+        (WebCore::ImmutableElementAttributeDataCacheKey::ImmutableElementAttributeDataCacheKey):
+        (WebCore::ImmutableElementAttributeDataCacheKey::operator!=):
+        (WebCore::ImmutableElementAttributeDataCacheKey::hash):
+        (ImmutableElementAttributeDataCacheEntry):
+        (WebCore::ImmutableElementAttributeDataCacheEntry::ImmutableElementAttributeDataCacheEntry):
+        (WebCore::DocumentSharedObjectPool::cachedImmutableElementAttributeData):
+        (WebCore::DocumentSharedObjectPool::DocumentSharedObjectPool):
+        (WebCore::DocumentSharedObjectPool::~DocumentSharedObjectPool):
+        * dom/DocumentSharedObjectPool.h: Added.
+        (DocumentSharedObjectPool):
+        (WebCore::DocumentSharedObjectPool::create):
+        * dom/Element.cpp:
+        (WebCore::Element::parserSetAttributes):
+
+            Moved the ElementAttributeData cache to DocumentSharedObjectPool.
+
 2012-12-02  John Bauman  <jbauman@chromium.org>
 
         [chromium] Let Pepper Flash use integrated GPU
index e52a168ff679ec10b7feead4993fb6bdcbca1b04..f17f84693a5db1af423d4a22d9e797094d09022c 100644 (file)
@@ -2757,6 +2757,8 @@ webcore_sources += \
        Source/WebCore/dom/DocumentOrderedMap.h \
        Source/WebCore/dom/DocumentParser.cpp \
        Source/WebCore/dom/DocumentParser.h \
+       Source/WebCore/dom/DocumentSharedObjectPool.cpp \
+       Source/WebCore/dom/DocumentSharedObjectPool.h \
     Source/WebCore/dom/DocumentStyleSheetCollection.cpp \
     Source/WebCore/dom/DocumentStyleSheetCollection.h \
        Source/WebCore/dom/DocumentTiming.h \
index 4535a46bf79ea635c667bf8b7c35f13f17fc2405..8abfc7a319f6b297182106fe7df0cd235467d6f9 100644 (file)
@@ -375,6 +375,7 @@ SOURCES += \
     dom/DocumentMarker.cpp \
     dom/DocumentOrderedMap.cpp \
     dom/DocumentParser.cpp \
+    dom/DocumentSharedObjectPool.cpp \
     dom/DocumentStyleSheetCollection.cpp \
     dom/DocumentType.cpp \
     dom/DOMCoreException.cpp \
@@ -1556,6 +1557,7 @@ HEADERS += \
     dom/DocumentMarker.h \
     dom/DocumentMarkerController.h \
     dom/DocumentOrderedMap.h \
+    dom/DocumentSharedObjectPool.h \
     dom/DocumentStyleSheetCollection.h \
     dom/DocumentType.h \
     dom/DOMError.h \
index e3d60139a4c7c6f376a3497d0cb8181a8248ccf7..03b057b65ed10e6b28406fc6543b2a684ab04860 100644 (file)
             'dom/DocumentMarkerController.h',
             'dom/DocumentOrderedMap.h',
             'dom/DocumentParser.h',
+            'dom/DocumentSharedObjectPool.h',
             'dom/DocumentStyleSheetCollection.h',
             'dom/DocumentTiming.h',
             'dom/DocumentType.h',
             'dom/DocumentMarker.cpp',
             'dom/DocumentOrderedMap.cpp',
             'dom/DocumentParser.cpp',
+            'dom/DocumentSharedObjectPool.cpp',
             'dom/DocumentStyleSheetCollection.cpp',
             'dom/DocumentType.cpp',
             'dom/ElementShadow.cpp',
index 9d92b809c82a0cfb9371969a45b499ecef665942..95dbddf99a7920bdc23da78520db96f0f7b2f7cc 100755 (executable)
                                RelativePath="..\dom\DocumentParser.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\dom\DocumentSharedObjectPool.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\dom\DocumentSharedObjectPool.h"
+                               >
+                       </File>
                        <File
                                RelativePath="..\dom\DocumentStyleSheetCollection.cpp"
                                >
index 3404cc15eeb5da7379a20ccc85fe9b76781a011e..edc46246987282df878d11083a4df4df97d98fad 100644 (file)
                AD03AAFA1468455300A39B5B /* CSSValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD03AAF81468453900A39B5B /* CSSValue.cpp */; };
                AD4495F3141FC08900541EDF /* EventListenerMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD4495F1141FC08900541EDF /* EventListenerMap.cpp */; };
                AD4495F4141FC08900541EDF /* EventListenerMap.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4495F2141FC08900541EDF /* EventListenerMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               AD6E71AC1668899D00320C13 /* DocumentSharedObjectPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD6E71AA1668899D00320C13 /* DocumentSharedObjectPool.cpp */; };
+               AD6E71AD1668899D00320C13 /* DocumentSharedObjectPool.h in Headers */ = {isa = PBXBuildFile; fileRef = AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */; };
                ADDF1AD71257CD9A0003A759 /* RenderSVGPath.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF1AD51257CD9A0003A759 /* RenderSVGPath.h */; };
                B10B6980140C174000BC1C26 /* WebVTTToken.h in Headers */ = {isa = PBXBuildFile; fileRef = B10B697D140C174000BC1C26 /* WebVTTToken.h */; };
                B10B6981140C174000BC1C26 /* WebVTTTokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B10B697E140C174000BC1C26 /* WebVTTTokenizer.cpp */; };
                AD03AAF81468453900A39B5B /* CSSValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSValue.cpp; sourceTree = "<group>"; };
                AD4495F1141FC08900541EDF /* EventListenerMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventListenerMap.cpp; sourceTree = "<group>"; };
                AD4495F2141FC08900541EDF /* EventListenerMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventListenerMap.h; sourceTree = "<group>"; };
+               AD6E71AA1668899D00320C13 /* DocumentSharedObjectPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentSharedObjectPool.cpp; sourceTree = "<group>"; };
+               AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentSharedObjectPool.h; sourceTree = "<group>"; };
                ADDF1AD41257CD9A0003A759 /* RenderSVGPath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGPath.cpp; sourceTree = "<group>"; };
                ADDF1AD51257CD9A0003A759 /* RenderSVGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGPath.h; sourceTree = "<group>"; };
                B10B697D140C174000BC1C26 /* WebVTTToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTToken.h; sourceTree = "<group>"; };
                                93EEC1F709C2877700C515D1 /* WheelEvent.idl */,
                                4123E568127B3041000FEEA7 /* WindowEventContext.cpp */,
                                4123E567127B3041000FEEA7 /* WindowEventContext.h */,
+                               AD6E71AA1668899D00320C13 /* DocumentSharedObjectPool.cpp */,
+                               AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */,
                        );
                        path = dom;
                        sourceTree = "<group>";
                                53EF766B16530A61004CBE49 /* SettingsMacros.h in Headers */,
                                447958041643B49A001E0A7F /* ParsedContentType.h in Headers */,
                                FB2C15C3165D649D0039C9F8 /* CachedSVGDocumentReference.h in Headers */,
+                               AD6E71AD1668899D00320C13 /* DocumentSharedObjectPool.h in Headers */,
                                31741AAD16636609008A5B7E /* SimulatedClickOptions.h in Headers */,
                                15B8B7C91652C5220036EF55 /* JSWebKitCSSMixFunctionValue.h in Headers */,
                                93F72AF31666EDFC002A02BD /* LayerPool.h in Headers */,
                                570B78BF1650CE81001DBE1B /* SelectRuleFeatureSet.cpp in Sources */,
                                1E50084816516AD800B7E098 /* RenderThemeMacShared.mm in Sources */,
                                CD7E05221651C28200C1201F /* WebCoreAVFResourceLoader.mm in Sources */,
+                               AD6E71AC1668899D00320C13 /* DocumentSharedObjectPool.cpp in Sources */,
                                447958051643B4B2001E0A7F /* ParsedContentType.cpp in Sources */,
                                15B8B7C81652C5220036EF55 /* JSWebKitCSSMixFunctionValue.cpp in Sources */,
                                86BA766E166427A8005BE5D1 /* FrameLoadRequest.cpp in Sources */,
index 506e267eaa245d9c14700c2d3cda41c8679b226a..2593e595acfcd7fb8579841f361e929e7e8ecbaa 100644 (file)
@@ -66,6 +66,7 @@
 #include "DocumentMarkerController.cpp"
 #include "DocumentOrderedMap.cpp"
 #include "DocumentParser.cpp"
+#include "DocumentSharedObjectPool.cpp"
 #include "DocumentType.cpp"
 #include "Element.cpp"
 #include "ElementAttributeData.cpp"
index d2cf7439b807fc6a0adea2bc8fc404a384a48f3c..260427697f1e947147e2fe56b5642af801a5eaab 100644 (file)
@@ -55,6 +55,7 @@
 #include "DocumentFragment.h"
 #include "DocumentLoader.h"
 #include "DocumentMarkerController.h"
+#include "DocumentSharedObjectPool.h"
 #include "DocumentStyleSheetCollection.h"
 #include "DocumentType.h"
 #include "Editor.h"
@@ -500,6 +501,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
     , m_scheduledTasksAreSuspended(false)
     , m_visualUpdatesAllowed(true)
     , m_visualUpdatesSuppressionTimer(this, &Document::visualUpdatesSuppressionTimerFired)
+    , m_sharedObjectPoolClearTimer(this, &Document::sharedObjectPoolClearTimerFired)
 #ifndef NDEBUG
     , m_didDispatchViewportPropertiesChanged(false)
 #endif
@@ -2491,6 +2493,10 @@ void Document::implicitClose()
 void Document::setParsing(bool b)
 {
     m_bParsing = b;
+
+    if (m_bParsing && !m_sharedObjectPool)
+        m_sharedObjectPool = DocumentSharedObjectPool::create();
+
     if (!m_bParsing && view())
         view()->scheduleRelayout();
 
@@ -4415,9 +4421,17 @@ void Document::finishedParsing()
         InspectorInstrumentation::domContentLoadedEventFired(f.get());
     }
 
-    // The ElementAttributeData sharing cache is only used during parsing since
-    // that's when the majority of immutable attribute data will be created.
-    m_immutableAttributeDataCache.clear();
+    // Schedule dropping of the DocumentSharedObjectPool. We keep it alive for a while after parsing finishes
+    // so that dynamically inserted content can also benefit from sharing optimizations.
+    // Note that we don't refresh the timer on pool access since that could lead to huge caches being kept
+    // alive indefinitely by something innocuous like JS setting .innerHTML repeatedly on a timer.
+    static const int timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds = 10;
+    m_sharedObjectPoolClearTimer.startOneShot(timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds);
+}
+
+void Document::sharedObjectPoolClearTimerFired(Timer<Document>*)
+{
+    m_sharedObjectPool.clear();
 }
 
 PassRefPtr<XPathExpression> Document::createExpression(const String& expression,
@@ -5860,65 +5874,6 @@ void Document::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
     info.addMember(m_listsInvalidatedAtDocument);
 }
 
-class ImmutableAttributeDataCacheKey {
-public:
-    ImmutableAttributeDataCacheKey(const Attribute* attributes, unsigned attributeCount)
-        : m_attributes(attributes)
-        , m_attributeCount(attributeCount)
-    { }
-
-    bool operator!=(const ImmutableAttributeDataCacheKey& other) const
-    {
-        if (m_attributeCount != other.m_attributeCount)
-            return true;
-        return memcmp(m_attributes, other.m_attributes, sizeof(Attribute) * m_attributeCount);
-    }
-
-    unsigned hash() const
-    {
-        return StringHasher::hashMemory(m_attributes, m_attributeCount * sizeof(Attribute));
-    }
-
-private:
-    const Attribute* m_attributes;
-    unsigned m_attributeCount;
-};
-
-struct ImmutableAttributeDataCacheEntry {
-    ImmutableAttributeDataCacheEntry(const ImmutableAttributeDataCacheKey& k, PassRefPtr<ElementAttributeData> v)
-        : key(k)
-        , value(v)
-    { }
-
-    ImmutableAttributeDataCacheKey key;
-    RefPtr<ElementAttributeData> value;
-};
-
-PassRefPtr<ElementAttributeData> Document::cachedImmutableAttributeData(const Vector<Attribute>& attributes)
-{
-    ASSERT(!attributes.isEmpty());
-
-    ImmutableAttributeDataCacheKey cacheKey(attributes.data(), attributes.size());
-    unsigned cacheHash = cacheKey.hash();
-
-    ImmutableAttributeDataCache::iterator cacheIterator = m_immutableAttributeDataCache.add(cacheHash, nullptr).iterator;
-    if (cacheIterator->value && cacheIterator->value->key != cacheKey)
-        cacheHash = 0;
-
-    RefPtr<ElementAttributeData> attributeData;
-    if (cacheHash && cacheIterator->value)
-        attributeData = cacheIterator->value->value;
-    else
-        attributeData = ElementAttributeData::createImmutable(attributes);
-
-    if (!cacheHash || cacheIterator->value)
-        return attributeData.release();
-
-    cacheIterator->value = adoptPtr(new ImmutableAttributeDataCacheEntry(ImmutableAttributeDataCacheKey(attributeData->immutableAttributeArray(), attributeData->length()), attributeData));
-
-    return attributeData.release();
-}
-
 bool Document::haveStylesheetsLoaded() const
 {
     return !m_styleSheetCollection->hasPendingSheets() || m_ignorePendingStylesheets;
index d697ce3a730baa0012a3e99ff8a79e942972ce7e..95e25c5c924c0cf7d420effc76f489b78a4a8ec7 100644 (file)
@@ -77,11 +77,11 @@ class DocumentFragment;
 class DocumentLoader;
 class DocumentMarkerController;
 class DocumentParser;
+class DocumentSharedObjectPool;
 class DocumentStyleSheetCollection;
 class DocumentType;
 class DocumentWeakReference;
 class Element;
-class ElementAttributeData;
 class EntityReference;
 class Event;
 class EventListener;
@@ -206,9 +206,6 @@ enum NodeListInvalidationType {
 };
 const int numNodeListInvalidationTypes = InvalidateOnAnyAttrChange + 1;
 
-struct ImmutableAttributeDataCacheEntry;
-typedef HashMap<unsigned, OwnPtr<ImmutableAttributeDataCacheEntry>, AlreadyHashed> ImmutableAttributeDataCache;
-
 class Document : public ContainerNode, public TreeScope, public ScriptExecutionContext {
 public:
     static PassRefPtr<Document> create(Frame* frame, const KURL& url)
@@ -1153,7 +1150,7 @@ public:
 
     virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
 
-    PassRefPtr<ElementAttributeData> cachedImmutableAttributeData(const Vector<Attribute>&);
+    DocumentSharedObjectPool* sharedObjectPool() { return m_sharedObjectPool.get(); }
 
     void didRemoveAllPendingStylesheet();
     void setNeedsNotifyRemoveAllPendingStylesheet() { m_needsNotifyRemoveAllPendingStylesheet = true; }
@@ -1515,7 +1512,10 @@ private:
     RefPtr<DOMSecurityPolicy> m_domSecurityPolicy;
 #endif
 
-    ImmutableAttributeDataCache m_immutableAttributeDataCache;
+    void sharedObjectPoolClearTimerFired(Timer<Document>*);
+    Timer<Document> m_sharedObjectPoolClearTimer;
+
+    OwnPtr<DocumentSharedObjectPool> m_sharedObjectPool;
 
 #ifndef NDEBUG
     bool m_didDispatchViewportPropertiesChanged;
diff --git a/Source/WebCore/dom/DocumentSharedObjectPool.cpp b/Source/WebCore/dom/DocumentSharedObjectPool.cpp
new file mode 100644 (file)
index 0000000..b85eff8
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "DocumentSharedObjectPool.h"
+
+#include "Attribute.h"
+#include "ElementAttributeData.h"
+
+namespace WebCore {
+
+class ImmutableElementAttributeDataCacheKey {
+public:
+    ImmutableElementAttributeDataCacheKey(const Attribute* attributes, unsigned attributeCount)
+        : m_attributes(attributes)
+        , m_attributeCount(attributeCount)
+    { }
+
+    bool operator!=(const ImmutableElementAttributeDataCacheKey& other) const
+    {
+        if (m_attributeCount != other.m_attributeCount)
+            return true;
+        return memcmp(m_attributes, other.m_attributes, sizeof(Attribute) * m_attributeCount);
+    }
+
+    unsigned hash() const
+    {
+        return StringHasher::hashMemory(m_attributes, m_attributeCount * sizeof(Attribute));
+    }
+
+private:
+    const Attribute* m_attributes;
+    unsigned m_attributeCount;
+};
+
+class ImmutableElementAttributeDataCacheEntry {
+public:
+    ImmutableElementAttributeDataCacheEntry(const ImmutableElementAttributeDataCacheKey& k, PassRefPtr<ElementAttributeData> v)
+        : key(k)
+        , value(v)
+    { }
+
+    ImmutableElementAttributeDataCacheKey key;
+    RefPtr<ElementAttributeData> value;
+};
+
+PassRefPtr<ElementAttributeData> DocumentSharedObjectPool::cachedImmutableElementAttributeData(const Vector<Attribute>& attributes)
+{
+    ASSERT(!attributes.isEmpty());
+
+    ImmutableElementAttributeDataCacheKey cacheKey(attributes.data(), attributes.size());
+    unsigned cacheHash = cacheKey.hash();
+
+    ImmutableElementAttributeDataCache::iterator cacheIterator = m_immutableElementAttributeDataCache.add(cacheHash, nullptr).iterator;
+    if (cacheIterator->value && cacheIterator->value->key != cacheKey)
+        cacheHash = 0;
+
+    RefPtr<ElementAttributeData> attributeData;
+    if (cacheHash && cacheIterator->value)
+        attributeData = cacheIterator->value->value;
+    else
+        attributeData = ElementAttributeData::createImmutable(attributes);
+
+    if (!cacheHash || cacheIterator->value)
+        return attributeData.release();
+
+    cacheIterator->value = adoptPtr(new ImmutableElementAttributeDataCacheEntry(ImmutableElementAttributeDataCacheKey(attributeData->immutableAttributeArray(), attributeData->length()), attributeData));
+
+    return attributeData.release();
+}
+
+DocumentSharedObjectPool::DocumentSharedObjectPool()
+{
+}
+
+DocumentSharedObjectPool::~DocumentSharedObjectPool()
+{
+}
+
+}
diff --git a/Source/WebCore/dom/DocumentSharedObjectPool.h b/Source/WebCore/dom/DocumentSharedObjectPool.h
new file mode 100644 (file)
index 0000000..540c913
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef DocumentSharedObjectPool_h
+#define DocumentSharedObjectPool_h
+
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class Attribute;
+class ElementAttributeData;
+class ImmutableElementAttributeDataCacheEntry;
+
+class DocumentSharedObjectPool {
+public:
+    static PassOwnPtr<DocumentSharedObjectPool> create() { return adoptPtr(new DocumentSharedObjectPool); }
+    ~DocumentSharedObjectPool();
+
+    PassRefPtr<ElementAttributeData> cachedImmutableElementAttributeData(const Vector<Attribute>&);
+
+private:
+    DocumentSharedObjectPool();
+
+    typedef HashMap<unsigned, OwnPtr<ImmutableElementAttributeDataCacheEntry>, AlreadyHashed> ImmutableElementAttributeDataCache;
+    ImmutableElementAttributeDataCache m_immutableElementAttributeDataCache;
+};
+
+}
+
+#endif
index ab0cb710965bae482a27178d64df2f76c839c9b6..4dc0c5df53a923bf9be9cf0aefe4273ed40d7fe4 100644 (file)
@@ -37,6 +37,7 @@
 #include "DatasetDOMStringMap.h"
 #include "Document.h"
 #include "DocumentFragment.h"
+#include "DocumentSharedObjectPool.h"
 #include "ElementRareData.h"
 #include "ExceptionCode.h"
 #include "FlowThreadController.h"
@@ -976,12 +977,10 @@ void Element::parserSetAttributes(const Vector<Attribute>& attributeVector, Frag
         }
     }
 
-    // When the document is in parsing state, we cache immutable ElementAttributeData objects with the
-    // input attribute vector as key. (This cache is held by Document.)
-    if (!document() || !document()->parsing())
-        m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
+    if (document() && document()->sharedObjectPool())
+        m_attributeData = document()->sharedObjectPool()->cachedImmutableElementAttributeData(filteredAttributes);
     else
-        m_attributeData = document()->cachedImmutableAttributeData(filteredAttributes);
+        m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
 
     // Iterate over the set of attributes we already have on the stack in case
     // attributeChanged mutates m_attributeData.