Title: [282227] branches/safari-612-branch/Source/WebCore
Revision
282227
Author
[email protected]
Date
2021-09-09 11:04:27 -0700 (Thu, 09 Sep 2021)

Log Message

Cherry-pick r282142. rdar://problem/82931317

    Add a fast path for atomizing strings when parsing HTML
    https://bugs.webkit.org/show_bug.cgi?id=229907
    rdar://82854612

    Reviewed by Yusuke Suzuki and Darin Adler.

    On various subtests in Speedometer 2, a nontrivial amount of time is spent mapping raw UChar data vectors into
    AtomStrings while parsing HTML tag names, attribute names and attribute values. Most of this happens underneath
    the AtomHTMLToken constructor, which computes a hash for each string in the process of adding it to the atom
    string table; the time it takes to compute this string hash increases linearly with the length of the string.

    However, over the course of the benchmark, the vast majority of AtomStrings created out of tag names, attribute
    names and attribute values are both:

    (1) Strings that we've already recently atomized, and
    (2) Usually distinguishable from other atom strings based solely on their first character, last character, and
        overall string length.

    As such, it's possible to slightly improve string atomization performance in this particular case (i.e. parsing
    HTML) by maintaining a smaller cache of recently atomized AtomStrings that we index using a simple, constant-
    time hash function that considers only the first character, last character, and length of the string. In terms
    of the cache hit rate in this AtomString cache, the default string hashing algorithm only barely outperforms
    this simple hash function on Speedometer (i.e., a cache hit rate of 99.24% using the default hash algorithm vs.
    99.15% using the "first/last character and length" hash).

    Using this technique, we can get a significant performance improvement on Speedometer by introducing two small,
    fixed-size (512 capacity) AtomString tables: one to hold tag names and attribute names, and another to hold
    attribute values (which seems to contain a much larger set of unique strings); we additionally use the cheap "2-
    char & length" hash algorithm described above to index into these fixed-size tables.

    This allows us to more efficiently atomize not only known tag and attribute names, but also custom element tag
    names and attribute names and values that tend to appear frequently in markup (e.g. due to using certain
    _javascript_ frameworks that get and set HTML attributes).

    * Sources.txt:
    * WebCore.xcodeproj/project.pbxproj:
    * html/parser/AtomHTMLToken.h:
    (WebCore::AtomHTMLToken::initializeAttributes):
    (WebCore::AtomHTMLToken::AtomHTMLToken):
    * html/parser/HTMLAtomStringCache.cpp: Added.
    (WebCore::HTMLAtomStringCache::cache):
    * html/parser/HTMLAtomStringCache.h: Added.

    Add a helper class that exposes three static inline helper methods: `makeTagOrAttributeName` and
    `makeAttributeValue`, which return AtomStrings for the given `Vector<UChar>` (consulting the corresponding
    cache if possible); and `clear`, which empties all cached atom strings.

    (WebCore::HTMLAtomStringCache::makeTagOrAttributeName):
    (WebCore::HTMLAtomStringCache::makeAttributeValue):
    (WebCore::HTMLAtomStringCache::clear):
    (WebCore::HTMLAtomStringCache::make):

    Additionally add an upper length limit for characters that we include in this cache; in practice, longer strings
    tend to be repeatedly atomized less frequently than shorter strings. The 36-character limit also allows for
    frequently-parsed (and atomized) UUIDs to be cached.

    (WebCore::HTMLAtomStringCache::cacheSlot):

    This hashing algorithm was inspired by `calculateWithTwoCharacters`, but with constants specifically chosen to
    minimize collisions between common HTML tag and attribute names.

    * page/MemoryRelease.cpp:
    (WebCore::releaseNoncriticalMemory):
    * page/cocoa/MemoryReleaseCocoa.mm:
    (WebCore::jettisonExpensiveObjectsOnTopLevelNavigation):

    Add logic to clear the HTML atom string cache upon receiving a low memory warning, and upon top-level
    navigation.

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

Modified Paths

Added Paths

Diff

Modified: branches/safari-612-branch/Source/WebCore/ChangeLog (282226 => 282227)


--- branches/safari-612-branch/Source/WebCore/ChangeLog	2021-09-09 18:01:36 UTC (rev 282226)
+++ branches/safari-612-branch/Source/WebCore/ChangeLog	2021-09-09 18:04:27 UTC (rev 282227)
@@ -1,3 +1,150 @@
+2021-09-09  Russell Epstein  <[email protected]>
+
+        Cherry-pick r282142. rdar://problem/82931317
+
+    Add a fast path for atomizing strings when parsing HTML
+    https://bugs.webkit.org/show_bug.cgi?id=229907
+    rdar://82854612
+    
+    Reviewed by Yusuke Suzuki and Darin Adler.
+    
+    On various subtests in Speedometer 2, a nontrivial amount of time is spent mapping raw UChar data vectors into
+    AtomStrings while parsing HTML tag names, attribute names and attribute values. Most of this happens underneath
+    the AtomHTMLToken constructor, which computes a hash for each string in the process of adding it to the atom
+    string table; the time it takes to compute this string hash increases linearly with the length of the string.
+    
+    However, over the course of the benchmark, the vast majority of AtomStrings created out of tag names, attribute
+    names and attribute values are both:
+    
+    (1) Strings that we've already recently atomized, and
+    (2) Usually distinguishable from other atom strings based solely on their first character, last character, and
+        overall string length.
+    
+    As such, it's possible to slightly improve string atomization performance in this particular case (i.e. parsing
+    HTML) by maintaining a smaller cache of recently atomized AtomStrings that we index using a simple, constant-
+    time hash function that considers only the first character, last character, and length of the string. In terms
+    of the cache hit rate in this AtomString cache, the default string hashing algorithm only barely outperforms
+    this simple hash function on Speedometer (i.e., a cache hit rate of 99.24% using the default hash algorithm vs.
+    99.15% using the "first/last character and length" hash).
+    
+    Using this technique, we can get a significant performance improvement on Speedometer by introducing two small,
+    fixed-size (512 capacity) AtomString tables: one to hold tag names and attribute names, and another to hold
+    attribute values (which seems to contain a much larger set of unique strings); we additionally use the cheap "2-
+    char & length" hash algorithm described above to index into these fixed-size tables.
+    
+    This allows us to more efficiently atomize not only known tag and attribute names, but also custom element tag
+    names and attribute names and values that tend to appear frequently in markup (e.g. due to using certain
+    _javascript_ frameworks that get and set HTML attributes).
+    
+    * Sources.txt:
+    * WebCore.xcodeproj/project.pbxproj:
+    * html/parser/AtomHTMLToken.h:
+    (WebCore::AtomHTMLToken::initializeAttributes):
+    (WebCore::AtomHTMLToken::AtomHTMLToken):
+    * html/parser/HTMLAtomStringCache.cpp: Added.
+    (WebCore::HTMLAtomStringCache::cache):
+    * html/parser/HTMLAtomStringCache.h: Added.
+    
+    Add a helper class that exposes three static inline helper methods: `makeTagOrAttributeName` and
+    `makeAttributeValue`, which return AtomStrings for the given `Vector<UChar>` (consulting the corresponding
+    cache if possible); and `clear`, which empties all cached atom strings.
+    
+    (WebCore::HTMLAtomStringCache::makeTagOrAttributeName):
+    (WebCore::HTMLAtomStringCache::makeAttributeValue):
+    (WebCore::HTMLAtomStringCache::clear):
+    (WebCore::HTMLAtomStringCache::make):
+    
+    Additionally add an upper length limit for characters that we include in this cache; in practice, longer strings
+    tend to be repeatedly atomized less frequently than shorter strings. The 36-character limit also allows for
+    frequently-parsed (and atomized) UUIDs to be cached.
+    
+    (WebCore::HTMLAtomStringCache::cacheSlot):
+    
+    This hashing algorithm was inspired by `calculateWithTwoCharacters`, but with constants specifically chosen to
+    minimize collisions between common HTML tag and attribute names.
+    
+    * page/MemoryRelease.cpp:
+    (WebCore::releaseNoncriticalMemory):
+    * page/cocoa/MemoryReleaseCocoa.mm:
+    (WebCore::jettisonExpensiveObjectsOnTopLevelNavigation):
+    
+    Add logic to clear the HTML atom string cache upon receiving a low memory warning, and upon top-level
+    navigation.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282142 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-08  Wenson Hsieh  <[email protected]>
+
+            Add a fast path for atomizing strings when parsing HTML
+            https://bugs.webkit.org/show_bug.cgi?id=229907
+            rdar://82854612
+
+            Reviewed by Yusuke Suzuki and Darin Adler.
+
+            On various subtests in Speedometer 2, a nontrivial amount of time is spent mapping raw UChar data vectors into
+            AtomStrings while parsing HTML tag names, attribute names and attribute values. Most of this happens underneath
+            the AtomHTMLToken constructor, which computes a hash for each string in the process of adding it to the atom
+            string table; the time it takes to compute this string hash increases linearly with the length of the string.
+
+            However, over the course of the benchmark, the vast majority of AtomStrings created out of tag names, attribute
+            names and attribute values are both:
+
+            (1) Strings that we've already recently atomized, and
+            (2) Usually distinguishable from other atom strings based solely on their first character, last character, and
+                overall string length.
+
+            As such, it's possible to slightly improve string atomization performance in this particular case (i.e. parsing
+            HTML) by maintaining a smaller cache of recently atomized AtomStrings that we index using a simple, constant-
+            time hash function that considers only the first character, last character, and length of the string. In terms
+            of the cache hit rate in this AtomString cache, the default string hashing algorithm only barely outperforms
+            this simple hash function on Speedometer (i.e., a cache hit rate of 99.24% using the default hash algorithm vs.
+            99.15% using the "first/last character and length" hash).
+
+            Using this technique, we can get a significant performance improvement on Speedometer by introducing two small,
+            fixed-size (512 capacity) AtomString tables: one to hold tag names and attribute names, and another to hold
+            attribute values (which seems to contain a much larger set of unique strings); we additionally use the cheap "2-
+            char & length" hash algorithm described above to index into these fixed-size tables.
+
+            This allows us to more efficiently atomize not only known tag and attribute names, but also custom element tag
+            names and attribute names and values that tend to appear frequently in markup (e.g. due to using certain
+            _javascript_ frameworks that get and set HTML attributes).
+
+            * Sources.txt:
+            * WebCore.xcodeproj/project.pbxproj:
+            * html/parser/AtomHTMLToken.h:
+            (WebCore::AtomHTMLToken::initializeAttributes):
+            (WebCore::AtomHTMLToken::AtomHTMLToken):
+            * html/parser/HTMLAtomStringCache.cpp: Added.
+            (WebCore::HTMLAtomStringCache::cache):
+            * html/parser/HTMLAtomStringCache.h: Added.
+
+            Add a helper class that exposes three static inline helper methods: `makeTagOrAttributeName` and
+            `makeAttributeValue`, which return AtomStrings for the given `Vector<UChar>` (consulting the corresponding
+            cache if possible); and `clear`, which empties all cached atom strings.
+
+            (WebCore::HTMLAtomStringCache::makeTagOrAttributeName):
+            (WebCore::HTMLAtomStringCache::makeAttributeValue):
+            (WebCore::HTMLAtomStringCache::clear):
+            (WebCore::HTMLAtomStringCache::make):
+
+            Additionally add an upper length limit for characters that we include in this cache; in practice, longer strings
+            tend to be repeatedly atomized less frequently than shorter strings. The 36-character limit also allows for
+            frequently-parsed (and atomized) UUIDs to be cached.
+
+            (WebCore::HTMLAtomStringCache::cacheSlot):
+
+            This hashing algorithm was inspired by `calculateWithTwoCharacters`, but with constants specifically chosen to
+            minimize collisions between common HTML tag and attribute names.
+
+            * page/MemoryRelease.cpp:
+            (WebCore::releaseNoncriticalMemory):
+            * page/cocoa/MemoryReleaseCocoa.mm:
+            (WebCore::jettisonExpensiveObjectsOnTopLevelNavigation):
+
+            Add logic to clear the HTML atom string cache upon receiving a low memory warning, and upon top-level
+            navigation.
+
 2021-09-01  Russell Epstein  <[email protected]>
 
         Cherry-pick r281817. rdar://problem/82652467

Modified: branches/safari-612-branch/Source/WebCore/Sources.txt (282226 => 282227)


--- branches/safari-612-branch/Source/WebCore/Sources.txt	2021-09-09 18:01:36 UTC (rev 282226)
+++ branches/safari-612-branch/Source/WebCore/Sources.txt	2021-09-09 18:04:27 UTC (rev 282227)
@@ -1302,6 +1302,7 @@
 html/canvas/WebGLVertexArrayObjectOES.cpp
 html/forms/FileIconLoader.cpp
 html/parser/CSSPreloadScanner.cpp
+html/parser/HTMLAtomStringCache.cpp
 html/parser/HTMLConstructionSite.cpp
 html/parser/HTMLDocumentParser.cpp
 html/parser/HTMLElementStack.cpp

Modified: branches/safari-612-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj (282226 => 282227)


--- branches/safari-612-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-09-09 18:01:36 UTC (rev 282226)
+++ branches/safari-612-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-09-09 18:04:27 UTC (rev 282227)
@@ -5384,6 +5384,7 @@
 		F48D2A7E2157182600C6752B /* FontAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2A712156DC0A00C6752B /* FontAttributes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F48D2AA52159740D00C6752B /* ColorCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2AA32159740D00C6752B /* ColorCocoa.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F49786881FF45FA500E060AB /* PasteboardItemInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F49786871FF45FA500E060AB /* PasteboardItemInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		F4B0018926E7F21F006EAABE /* HTMLAtomStringCache.h in Headers */ = {isa = PBXBuildFile; fileRef = F4B0018726E7F21F006EAABE /* HTMLAtomStringCache.h */; };
 		F4B2A909265030BA009E7286 /* DataDetectorHighlight.h in Headers */ = {isa = PBXBuildFile; fileRef = F4B2A90626502BA0009E7286 /* DataDetectorHighlight.h */; };
 		F4B422C4220C0568009E1E7D /* DOMPasteAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = F4B422C2220C0000009E1E7D /* DOMPasteAccess.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F4BFB9851E1DDF9B00862C24 /* DumpEditingHistory.js in Copy Scripts */ = {isa = PBXBuildFile; fileRef = F48389831E1DDF2B0076B7EA /* DumpEditingHistory.js */; };
@@ -16555,6 +16556,8 @@
 		F48D2AA42159740D00C6752B /* ColorCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ColorCocoa.mm; sourceTree = "<group>"; };
 		F49786871FF45FA500E060AB /* PasteboardItemInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PasteboardItemInfo.h; sourceTree = "<group>"; };
 		F49E98E421DEE6C1009AE55E /* EditAction.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = EditAction.cpp; sourceTree = "<group>"; };
+		F4B0018726E7F21F006EAABE /* HTMLAtomStringCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLAtomStringCache.h; sourceTree = "<group>"; };
+		F4B0018826E7F21F006EAABE /* HTMLAtomStringCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLAtomStringCache.cpp; sourceTree = "<group>"; };
 		F4B2A90626502BA0009E7286 /* DataDetectorHighlight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataDetectorHighlight.h; sourceTree = "<group>"; };
 		F4B2A90826502BC0009E7286 /* DataDetectorHighlight.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DataDetectorHighlight.mm; sourceTree = "<group>"; };
 		F4B2A90C265087E4009E7286 /* ImageOverlayControllerMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImageOverlayControllerMac.mm; sourceTree = "<group>"; };
@@ -24035,6 +24038,8 @@
 				97C1F552122855CB00EDE617 /* AtomHTMLToken.h */,
 				977B3849122883E900B81FF8 /* CSSPreloadScanner.cpp */,
 				977B384A122883E900B81FF8 /* CSSPreloadScanner.h */,
+				F4B0018826E7F21F006EAABE /* HTMLAtomStringCache.cpp */,
+				F4B0018726E7F21F006EAABE /* HTMLAtomStringCache.h */,
 				977B384B122883E900B81FF8 /* HTMLConstructionSite.cpp */,
 				977B384C122883E900B81FF8 /* HTMLConstructionSite.h */,
 				977B384D122883E900B81FF8 /* HTMLDocumentParser.cpp */,
@@ -32140,6 +32145,7 @@
 				BC97E23A109144950010D361 /* HTMLAllCollection.h in Headers */,
 				A8CFF7AB0A156978000A4234 /* HTMLAnchorElement.h in Headers */,
 				A8EA7D2E0A19385500A8EF5F /* HTMLAreaElement.h in Headers */,
+				F4B0018926E7F21F006EAABE /* HTMLAtomStringCache.h in Headers */,
 				7C5F28FC1A827D8400C0F31F /* HTMLAttachmentElement.h in Headers */,
 				E44613A20CD6331000FADA75 /* HTMLAudioElement.h in Headers */,
 				A871DC1F0A15205700B12A68 /* HTMLBaseElement.h in Headers */,

Modified: branches/safari-612-branch/Source/WebCore/html/parser/AtomHTMLToken.h (282226 => 282227)


--- branches/safari-612-branch/Source/WebCore/html/parser/AtomHTMLToken.h	2021-09-09 18:01:36 UTC (rev 282226)
+++ branches/safari-612-branch/Source/WebCore/html/parser/AtomHTMLToken.h	2021-09-09 18:04:27 UTC (rev 282227)
@@ -26,6 +26,7 @@
 
 #pragma once
 
+#include "HTMLAtomStringCache.h"
 #include "HTMLToken.h"
 
 namespace WebCore {
@@ -202,11 +203,11 @@
         if (attribute.name.isEmpty())
             continue;
 
-        AtomString localName(attribute.name);
+        auto localName = HTMLAtomStringCache::makeTagOrAttributeName(attribute.name);
 
         // FIXME: This is N^2 for the number of attributes.
         if (!hasAttribute(m_attributes, localName))
-            m_attributes.uncheckedAppend(Attribute(QualifiedName(nullAtom(), localName, nullAtom()), AtomString(attribute.value)));
+            m_attributes.uncheckedAppend(Attribute(QualifiedName(nullAtom(), localName, nullAtom()), HTMLAtomStringCache::makeAttributeValue(attribute.value)));
     }
 }
 
@@ -218,7 +219,7 @@
         ASSERT_NOT_REACHED();
         return;
     case HTMLToken::DOCTYPE:
-        m_name = AtomString(token.name());
+        m_name = HTMLAtomStringCache::makeTagOrAttributeName(token.name());
         m_doctypeData = token.releaseDoctypeData();
         return;
     case HTMLToken::EndOfFile:
@@ -226,7 +227,7 @@
     case HTMLToken::StartTag:
     case HTMLToken::EndTag:
         m_selfClosing = token.selfClosing();
-        m_name = AtomString(token.name());
+        m_name = HTMLAtomStringCache::makeTagOrAttributeName(token.name());
         initializeAttributes(token.attributes());
         return;
     case HTMLToken::Comment:

Added: branches/safari-612-branch/Source/WebCore/html/parser/HTMLAtomStringCache.cpp (0 => 282227)


--- branches/safari-612-branch/Source/WebCore/html/parser/HTMLAtomStringCache.cpp	                        (rev 0)
+++ branches/safari-612-branch/Source/WebCore/html/parser/HTMLAtomStringCache.cpp	2021-09-09 18:04:27 UTC (rev 282227)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 "HTMLAtomStringCache.h"
+
+namespace WebCore {
+
+HTMLAtomStringCache::Cache& HTMLAtomStringCache::cache(Type type)
+{
+    static MainThreadNeverDestroyed<Cache> caches[2];
+    return caches[static_cast<size_t>(type)].get();
+}
+
+} // namespace WebCore

Added: branches/safari-612-branch/Source/WebCore/html/parser/HTMLAtomStringCache.h (0 => 282227)


--- branches/safari-612-branch/Source/WebCore/html/parser/HTMLAtomStringCache.h	                        (rev 0)
+++ branches/safari-612-branch/Source/WebCore/html/parser/HTMLAtomStringCache.h	2021-09-09 18:04:27 UTC (rev 282227)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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.
+ */
+
+#pragma once
+
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Vector.h>
+#include <wtf/text/AtomString.h>
+
+namespace WebCore {
+
+class HTMLAtomStringCache {
+public:
+    template<size_t inlineCapacity>
+    ALWAYS_INLINE static AtomString makeTagOrAttributeName(const Vector<UChar, inlineCapacity>& string)
+    {
+        return make<Type::TagOrAttributeName>(string);
+    }
+
+    template<size_t inlineCapacity>
+    ALWAYS_INLINE static AtomString makeAttributeValue(const Vector<UChar, inlineCapacity>& string)
+    {
+        return make<Type::AttributeValue>(string);
+    }
+
+    ALWAYS_INLINE static void clear()
+    {
+        // FIXME (webkit.org/b/230019): We should try to find more opportunities to clear this cache without hindering this performance optimization.
+        cache(Type::TagOrAttributeName).fill({ });
+        cache(Type::AttributeValue).fill({ });
+    }
+
+private:
+    enum class Type : bool { TagOrAttributeName, AttributeValue };
+
+    template<HTMLAtomStringCache::Type type, size_t inlineCapacity>
+    ALWAYS_INLINE static AtomString make(const Vector<UChar, inlineCapacity>& string)
+    {
+        if (string.isEmpty())
+            return emptyAtom();
+
+        auto length = string.size();
+        if (length > maxStringLengthForCache)
+            return AtomString(string);
+
+        auto firstCharacter = string[0];
+        auto lastCharacter = string[length - 1];
+        auto& slot = cacheSlot(type, firstCharacter, lastCharacter, length);
+        if (!equal(slot.impl(), string.data(), length)) {
+            AtomString result(string);
+            slot = result;
+            return result;
+        }
+
+        return slot;
+    }
+
+    ALWAYS_INLINE static AtomString& cacheSlot(Type type, UChar firstCharacter, UChar lastCharacter, UChar length)
+    {
+        unsigned hash = (firstCharacter << 6) ^ ((lastCharacter << 14) ^ firstCharacter);
+        hash += (hash >> 14) + (length << 14);
+        hash ^= hash << 14;
+        return cache(type)[(hash + (hash >> 6)) % capacity];
+    }
+
+    static constexpr auto maxStringLengthForCache = 36;
+    static constexpr auto capacity = 512;
+    using Cache = std::array<AtomString, capacity>;
+    static Cache& cache(Type);
+};
+
+} // namespace WebCore

Modified: branches/safari-612-branch/Source/WebCore/page/MemoryRelease.cpp (282226 => 282227)


--- branches/safari-612-branch/Source/WebCore/page/MemoryRelease.cpp	2021-09-09 18:01:36 UTC (rev 282226)
+++ branches/safari-612-branch/Source/WebCore/page/MemoryRelease.cpp	2021-09-09 18:04:27 UTC (rev 282227)
@@ -38,6 +38,7 @@
 #include "FontCache.h"
 #include "Frame.h"
 #include "GCController.h"
+#include "HTMLAtomStringCache.h"
 #include "HTMLMediaElement.h"
 #include "InlineStyleSheetOwner.h"
 #include "InspectorInstrumentation.h"
@@ -85,6 +86,7 @@
         MemoryCache::singleton().pruneDeadResourcesToSize(0);
 
     InlineStyleSheetOwner::clearCache();
+    HTMLAtomStringCache::clear();
 }
 
 static void releaseCriticalMemory(Synchronous synchronous, MaintainBackForwardCache maintainBackForwardCache, MaintainMemoryCache maintainMemoryCache)

Modified: branches/safari-612-branch/Source/WebCore/page/cocoa/MemoryReleaseCocoa.mm (282226 => 282227)


--- branches/safari-612-branch/Source/WebCore/page/cocoa/MemoryReleaseCocoa.mm	2021-09-09 18:01:36 UTC (rev 282226)
+++ branches/safari-612-branch/Source/WebCore/page/cocoa/MemoryReleaseCocoa.mm	2021-09-09 18:04:27 UTC (rev 282227)
@@ -28,6 +28,7 @@
 
 #import "FontFamilySpecificationCoreText.h"
 #import "GCController.h"
+#import "HTMLAtomStringCache.h"
 #import "IOSurfacePool.h"
 #import "LayerPool.h"
 #import "LocaleCocoa.h"
@@ -83,7 +84,6 @@
 
 void jettisonExpensiveObjectsOnTopLevelNavigation()
 {
-#if PLATFORM(IOS_FAMILY)
     // Protect against doing excessive jettisoning during repeated navigations.
     const auto minimumTimeSinceNavigation = 2_s;
 
@@ -95,10 +95,13 @@
     if (!shouldJettison)
         return;
 
+#if PLATFORM(IOS_FAMILY)
     // Throw away linked JS code. Linked code is tied to a global object and is not reusable.
     // The immediate memory savings outweigh the cost of recompilation in case we go back again.
     GCController::singleton().deleteAllLinkedCode(JSC::DeleteAllCodeIfNotCollecting);
 #endif
+
+    HTMLAtomStringCache::clear();
 }
 
 void registerMemoryReleaseNotifyCallbacks()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to