Title: [199360] trunk/Source/WebCore
Revision
199360
Author
[email protected]
Date
2016-04-12 09:21:50 -0700 (Tue, 12 Apr 2016)

Log Message

Lazily update tokens in DOMTokenList when the associated attribute value changes
https://bugs.webkit.org/show_bug.cgi?id=156474

Reviewed by Ryosuke Niwa.

Lazily update tokens in DOMTokenList when the associated attribute value
changes for performance. Constructing the sanitized vector of tokens
every time the associated Element attribute changes is too expensive.
Instead, we mark the vector as dirty whenever the attribute changes, and
we only construct the sanitized vector when it is actually required.

Also do some renaming for clarity.

There is no web-exposed behavior change.

* dom/Element.cpp:
(WebCore::Element::classAttributeChanged):
* html/DOMTokenList.cpp:
(WebCore::DOMTokenList::contains):
(WebCore::DOMTokenList::addInternal):
(WebCore::DOMTokenList::removeInternal):
(WebCore::DOMTokenList::toggle):
(WebCore::DOMTokenList::value):
(WebCore::DOMTokenList::setValue):
(WebCore::DOMTokenList::updateTokensFromAttributeValue):
(WebCore::DOMTokenList::associatedAttributeValueChanged):
(WebCore::DOMTokenList::updateAssociatedAttributeFromTokens):
(WebCore::DOMTokenList::tokens):
(WebCore::DOMTokenList::DOMTokenList): Deleted.
* html/DOMTokenList.h:
(WebCore::DOMTokenList::tokens):
(WebCore::DOMTokenList::length):
(WebCore::DOMTokenList::item):
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::parseAttribute):
* html/HTMLIFrameElement.cpp:
(WebCore::HTMLIFrameElement::parseAttribute):
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::parseAttribute):
* html/HTMLOutputElement.cpp:
(WebCore::HTMLOutputElement::parseAttribute):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (199359 => 199360)


--- trunk/Source/WebCore/ChangeLog	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/ChangeLog	2016-04-12 16:21:50 UTC (rev 199360)
@@ -1,3 +1,47 @@
+2016-04-12  Chris Dumez  <[email protected]>
+
+        Lazily update tokens in DOMTokenList when the associated attribute value changes
+        https://bugs.webkit.org/show_bug.cgi?id=156474
+
+        Reviewed by Ryosuke Niwa.
+
+        Lazily update tokens in DOMTokenList when the associated attribute value
+        changes for performance. Constructing the sanitized vector of tokens
+        every time the associated Element attribute changes is too expensive.
+        Instead, we mark the vector as dirty whenever the attribute changes, and
+        we only construct the sanitized vector when it is actually required.
+
+        Also do some renaming for clarity.
+
+        There is no web-exposed behavior change.
+
+        * dom/Element.cpp:
+        (WebCore::Element::classAttributeChanged):
+        * html/DOMTokenList.cpp:
+        (WebCore::DOMTokenList::contains):
+        (WebCore::DOMTokenList::addInternal):
+        (WebCore::DOMTokenList::removeInternal):
+        (WebCore::DOMTokenList::toggle):
+        (WebCore::DOMTokenList::value):
+        (WebCore::DOMTokenList::setValue):
+        (WebCore::DOMTokenList::updateTokensFromAttributeValue):
+        (WebCore::DOMTokenList::associatedAttributeValueChanged):
+        (WebCore::DOMTokenList::updateAssociatedAttributeFromTokens):
+        (WebCore::DOMTokenList::tokens):
+        (WebCore::DOMTokenList::DOMTokenList): Deleted.
+        * html/DOMTokenList.h:
+        (WebCore::DOMTokenList::tokens):
+        (WebCore::DOMTokenList::length):
+        (WebCore::DOMTokenList::item):
+        * html/HTMLAnchorElement.cpp:
+        (WebCore::HTMLAnchorElement::parseAttribute):
+        * html/HTMLIFrameElement.cpp:
+        (WebCore::HTMLIFrameElement::parseAttribute):
+        * html/HTMLLinkElement.cpp:
+        (WebCore::HTMLLinkElement::parseAttribute):
+        * html/HTMLOutputElement.cpp:
+        (WebCore::HTMLOutputElement::parseAttribute):
+
 2016-04-12  Darin Adler  <[email protected]>
 
         Remove UsePointersEvenForNonNullableObjectArguments from HTMLMediaElement

Modified: trunk/Source/WebCore/dom/Element.cpp (199359 => 199360)


--- trunk/Source/WebCore/dom/Element.cpp	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/dom/Element.cpp	2016-04-12 16:21:50 UTC (rev 199360)
@@ -1330,7 +1330,7 @@
 
     if (hasRareData()) {
         if (auto* classList = elementRareData()->classList())
-            classList->attributeValueChanged(newClassString);
+            classList->associatedAttributeValueChanged(newClassString);
     }
 }
 

Modified: trunk/Source/WebCore/html/DOMTokenList.cpp (199359 => 199360)


--- trunk/Source/WebCore/html/DOMTokenList.cpp	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/DOMTokenList.cpp	2016-04-12 16:21:50 UTC (rev 199360)
@@ -40,7 +40,6 @@
     : m_element(element)
     , m_attributeName(attributeName)
 {
-    setValueInternal(m_element.getAttribute(m_attributeName));
 }
 
 bool DOMTokenList::validateToken(const String& token, ExceptionCode& ec)
@@ -72,26 +71,27 @@
 
 bool DOMTokenList::contains(const AtomicString& token) const
 {
-    return m_tokens.contains(token);
+    return tokens().contains(token);
 }
 
-inline void DOMTokenList::addInternal(const String* tokens, size_t length, ExceptionCode& ec)
+inline void DOMTokenList::addInternal(const String* newTokens, size_t length, ExceptionCode& ec)
 {
     // This is usually called with a single token.
-    Vector<AtomicString, 1> uniqueTokens;
-    uniqueTokens.reserveInitialCapacity(length);
+    Vector<AtomicString, 1> uniqueNewTokens;
+    uniqueNewTokens.reserveInitialCapacity(length);
 
+    auto& tokens = this->tokens();
     for (size_t i = 0; i < length; ++i) {
-        if (!validateToken(tokens[i], ec))
+        if (!validateToken(newTokens[i], ec))
             return;
-        if (!m_tokens.contains(tokens[i]) && !uniqueTokens.contains(tokens[i]))
-            uniqueTokens.uncheckedAppend(tokens[i]);
+        if (!tokens.contains(newTokens[i]) && !uniqueNewTokens.contains(newTokens[i]))
+            uniqueNewTokens.uncheckedAppend(newTokens[i]);
     }
 
-    if (!uniqueTokens.isEmpty())
-        m_tokens.appendVector(uniqueTokens);
+    if (!uniqueNewTokens.isEmpty())
+        tokens.appendVector(uniqueNewTokens);
 
-    updateAfterTokenChange();
+    updateAssociatedAttributeFromTokens();
 }
 
 void DOMTokenList::add(const Vector<String>& tokens, ExceptionCode& ec)
@@ -104,15 +104,16 @@
     addInternal(&token.string(), 1, ec);
 }
 
-inline void DOMTokenList::removeInternal(const String* tokens, size_t length, ExceptionCode& ec)
+inline void DOMTokenList::removeInternal(const String* tokensToRemove, size_t length, ExceptionCode& ec)
 {
-    if (!validateTokens(tokens, length, ec))
+    if (!validateTokens(tokensToRemove, length, ec))
         return;
 
+    auto& tokens = this->tokens();
     for (size_t i = 0; i < length; ++i)
-        m_tokens.removeFirst(tokens[i]);
+        tokens.removeFirst(tokensToRemove[i]);
 
-    updateAfterTokenChange();
+    updateAssociatedAttributeFromTokens();
 }
 
 void DOMTokenList::remove(const Vector<String>& tokens, ExceptionCode& ec)
@@ -130,10 +131,12 @@
     if (!validateToken(token, ec))
         return false;
 
-    if (m_tokens.contains(token)) {
+    auto& tokens = this->tokens();
+
+    if (tokens.contains(token)) {
         if (!force.valueOr(false)) {
-            m_tokens.removeFirst(token);
-            updateAfterTokenChange();
+            tokens.removeFirst(token);
+            updateAssociatedAttributeFromTokens();
             return false;
         }
         return true;
@@ -142,8 +145,8 @@
     if (force && !force.value())
         return false;
 
-    m_tokens.append(token);
-    updateAfterTokenChange();
+    tokens.append(token);
+    updateAssociatedAttributeFromTokens();
     return true;
 }
 
@@ -152,7 +155,7 @@
     if (m_cachedValue.isNull()) {
         // https://dom.spec.whatwg.org/#concept-ordered-set-serializer
         StringBuilder builder;
-        for (auto& token : m_tokens) {
+        for (auto& token : tokens()) {
             if (!builder.isEmpty())
                 builder.append(' ');
             builder.append(token);
@@ -160,16 +163,17 @@
         m_cachedValue = builder.toAtomicString();
         ASSERT(!m_cachedValue.isNull());
     }
+    ASSERT(!m_tokensNeedUpdating);
     return m_cachedValue;
 }
 
 void DOMTokenList::setValue(const String& value)
 {
-    setValueInternal(value);
-    updateAfterTokenChange();
+    updateTokensFromAttributeValue(value);
+    updateAssociatedAttributeFromTokens();
 }
 
-void DOMTokenList::setValueInternal(const WTF::String& value)
+void DOMTokenList::updateTokensFromAttributeValue(const String& value)
 {
     // Clear tokens but not capacity.
     m_tokens.shrink(0);
@@ -195,24 +199,38 @@
     }
 
     m_tokens.shrinkToFit();
+    m_tokensNeedUpdating = false;
     m_cachedValue = nullAtom;
 }
 
-void DOMTokenList::attributeValueChanged(const AtomicString& newValue)
+void DOMTokenList::associatedAttributeValueChanged(const AtomicString&)
 {
     // Do not reset the DOMTokenList value if the attribute value was changed by us.
-    if (m_isUpdatingAttributeValue)
+    if (m_inUpdateAssociatedAttributeFromTokens)
         return;
 
-    setValueInternal(newValue);
+    m_tokensNeedUpdating = true;
+    m_cachedValue = nullAtom;
 }
 
-void DOMTokenList::updateAfterTokenChange()
+// https://dom.spec.whatwg.org/#concept-dtl-update
+void DOMTokenList::updateAssociatedAttributeFromTokens()
 {
+    ASSERT(!m_tokensNeedUpdating);
+
     m_cachedValue = nullAtom;
 
-    TemporaryChange<bool> inAttributeUpdate(m_isUpdatingAttributeValue, true);
-    m_element.setAttribute(m_attributeName, value());
+    TemporaryChange<bool> inAttributeUpdate(m_inUpdateAssociatedAttributeFromTokens, true);
+    m_element.setAttributeWithoutSynchronization(m_attributeName, value());
+    ASSERT_WITH_MESSAGE(m_cachedValue, "Calling value() should have cached its results");
 }
 
+Vector<AtomicString>& DOMTokenList::tokens()
+{
+    if (m_tokensNeedUpdating)
+        updateTokensFromAttributeValue(m_element.fastGetAttribute(m_attributeName));
+    ASSERT(!m_tokensNeedUpdating);
+    return m_tokens;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/DOMTokenList.h (199359 => 199360)


--- trunk/Source/WebCore/html/DOMTokenList.h	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/DOMTokenList.h	2016-04-12 16:21:50 UTC (rev 199360)
@@ -39,8 +39,9 @@
     WTF_MAKE_NONCOPYABLE(DOMTokenList); WTF_MAKE_FAST_ALLOCATED;
 public:
     DOMTokenList(Element&, const QualifiedName& attributeName);
-    void attributeValueChanged(const AtomicString&);
 
+    void associatedAttributeValueChanged(const AtomicString&);
+
     void ref() { m_element.ref(); }
     void deref() { m_element.deref(); }
 
@@ -62,9 +63,12 @@
     const AtomicString& value() const;
 
 private:
-    void setValueInternal(const String&);
-    void updateAfterTokenChange();
+    void updateTokensFromAttributeValue(const String&);
+    void updateAssociatedAttributeFromTokens();
 
+    Vector<AtomicString>& tokens();
+    const Vector<AtomicString>& tokens() const { return const_cast<DOMTokenList&>(*this).tokens(); }
+
     static bool validateToken(const String&, ExceptionCode&);
     static bool validateTokens(const String* tokens, size_t length, ExceptionCode&);
     void addInternal(const String* tokens, size_t length, ExceptionCode&);
@@ -72,19 +76,21 @@
 
     Element& m_element;
     const WebCore::QualifiedName& m_attributeName;
-    bool m_isUpdatingAttributeValue { false };
+    bool m_inUpdateAssociatedAttributeFromTokens { false };
+    bool m_tokensNeedUpdating { true };
     Vector<AtomicString> m_tokens;
     mutable AtomicString m_cachedValue;
 };
 
 inline unsigned DOMTokenList::length() const
 {
-    return m_tokens.size();
+    return tokens().size();
 }
 
 inline const AtomicString& DOMTokenList::item(unsigned index) const
 {
-    return index < m_tokens.size() ? m_tokens[index] : nullAtom;
+    auto& tokens = this->tokens();
+    return index < tokens.size() ? tokens[index] : nullAtom;
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/HTMLAnchorElement.cpp (199359 => 199360)


--- trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2016-04-12 16:21:50 UTC (rev 199360)
@@ -252,7 +252,7 @@
         if (SpaceSplitString::spaceSplitStringContainsValue(value, "noreferrer", true))
             m_linkRelations |= RelationNoReferrer;
         if (m_relList)
-            m_relList->attributeValueChanged(value);
+            m_relList->associatedAttributeValueChanged(value);
     }
     else
         HTMLElement::parseAttribute(name, value);

Modified: trunk/Source/WebCore/html/HTMLIFrameElement.cpp (199359 => 199360)


--- trunk/Source/WebCore/html/HTMLIFrameElement.cpp	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLIFrameElement.cpp	2016-04-12 16:21:50 UTC (rev 199360)
@@ -85,7 +85,7 @@
 {
     if (name == sandboxAttr) {
         if (m_sandbox)
-            m_sandbox->attributeValueChanged(value);
+            m_sandbox->associatedAttributeValueChanged(value);
 
         String invalidTokens;
         setSandboxFlags(value.isNull() ? SandboxNone : SecurityContext::parseSandboxPolicy(value, invalidTokens));

Modified: trunk/Source/WebCore/html/HTMLLinkElement.cpp (199359 => 199360)


--- trunk/Source/WebCore/html/HTMLLinkElement.cpp	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLLinkElement.cpp	2016-04-12 16:21:50 UTC (rev 199360)
@@ -141,7 +141,7 @@
     if (name == relAttr) {
         m_relAttribute = LinkRelAttribute(value);
         if (m_relList)
-            m_relList->attributeValueChanged(value);
+            m_relList->associatedAttributeValueChanged(value);
         process();
         return;
     }
@@ -160,7 +160,7 @@
     }
     if (name == sizesAttr) {
         if (m_sizes)
-            m_sizes->attributeValueChanged(value);
+            m_sizes->associatedAttributeValueChanged(value);
         process();
         return;
     }

Modified: trunk/Source/WebCore/html/HTMLOutputElement.cpp (199359 => 199360)


--- trunk/Source/WebCore/html/HTMLOutputElement.cpp	2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLOutputElement.cpp	2016-04-12 16:21:50 UTC (rev 199360)
@@ -68,7 +68,7 @@
 {
     if (name == forAttr) {
         if (m_tokens)
-            m_tokens->attributeValueChanged(value);
+            m_tokens->associatedAttributeValueChanged(value);
     } else
         HTMLFormControlElement::parseAttribute(name, value);
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to