Compact sizeof(HTMLAnchorElement) and sizeof(HTMLLinkElement)
https://bugs.webkit.org/show_bug.cgi?id=206343

Reviewed by Ryosuke Niwa.

Data from Membuster is saying that HTMLAnchorElement is relatively frequently allocated
element (1252 elements are kept) while sizeof(HTMLAnchorElement) is not optimized well.
We also found that HTMLLinkElement is too large while it has so many paddings and opportunities
to optimize it. This patch shrinks them.

We also found that SharedStringHashHash's upper 32bit is always zero, and nobody is using this
effectively. We make it 32bit.

No behavior change.

* html/HTMLAnchorElement.h:
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::HTMLLinkElement):
(WebCore::HTMLLinkElement::process):
* html/HTMLLinkElement.h:
* html/LinkIconCollector.h:
* html/LinkIconType.h:
* html/LinkRelAttribute.cpp:
(WebCore::LinkRelAttribute::LinkRelAttribute):
* html/LinkRelAttribute.h:
(): Deleted.
* page/Page.h:
* page/VisitedLinkStore.h:
* platform/SharedStringHash.h:
(WebCore::SharedStringHashHash::avoidDeletedValue): Deleted.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@254739 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index c3f7c6f..07a31cd 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,36 @@
+2020-01-16  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        Compact sizeof(HTMLAnchorElement) and sizeof(HTMLLinkElement)
+        https://bugs.webkit.org/show_bug.cgi?id=206343
+
+        Reviewed by Ryosuke Niwa.
+
+        Data from Membuster is saying that HTMLAnchorElement is relatively frequently allocated
+        element (1252 elements are kept) while sizeof(HTMLAnchorElement) is not optimized well.
+        We also found that HTMLLinkElement is too large while it has so many paddings and opportunities
+        to optimize it. This patch shrinks them.
+
+        We also found that SharedStringHashHash's upper 32bit is always zero, and nobody is using this
+        effectively. We make it 32bit.
+
+        No behavior change.
+
+        * html/HTMLAnchorElement.h:
+        * html/HTMLLinkElement.cpp:
+        (WebCore::HTMLLinkElement::HTMLLinkElement):
+        (WebCore::HTMLLinkElement::process):
+        * html/HTMLLinkElement.h:
+        * html/LinkIconCollector.h:
+        * html/LinkIconType.h:
+        * html/LinkRelAttribute.cpp:
+        (WebCore::LinkRelAttribute::LinkRelAttribute):
+        * html/LinkRelAttribute.h:
+        (): Deleted.
+        * page/Page.h:
+        * page/VisitedLinkStore.h:
+        * platform/SharedStringHash.h:
+        (WebCore::SharedStringHashHash::avoidDeletedValue): Deleted.
+
 2020-01-16  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][IFC] Optimize LineLayoutContext::tryAddingInlineItems for the most common inline content
diff --git a/Source/WebCore/html/HTMLAnchorElement.h b/Source/WebCore/html/HTMLAnchorElement.h
index 0245090..de2834d 100644
--- a/Source/WebCore/html/HTMLAnchorElement.h
+++ b/Source/WebCore/html/HTMLAnchorElement.h
@@ -35,7 +35,7 @@
 class DOMTokenList;
 
 // Link relation bitmask values.
-enum class Relation {
+enum class Relation : uint8_t {
     NoReferrer = 1 << 0,
     NoOpener = 1 << 1,
     Opener = 1 << 2,
@@ -117,7 +117,7 @@
     OptionSet<Relation> m_linkRelations;
 
     // This is computed only once and must not be affected by subsequent URL changes.
-    mutable Optional<SharedStringHash> m_storedVisitedLinkHash;
+    mutable Markable<SharedStringHash, SharedStringHashMarkableTraits> m_storedVisitedLinkHash;
 
     mutable std::unique_ptr<DOMTokenList> m_relList;
 };
diff --git a/Source/WebCore/html/HTMLLinkElement.cpp b/Source/WebCore/html/HTMLLinkElement.cpp
index 396c937..5377a4c 100644
--- a/Source/WebCore/html/HTMLLinkElement.cpp
+++ b/Source/WebCore/html/HTMLLinkElement.cpp
@@ -62,7 +62,7 @@
 #include "SubresourceIntegrity.h"
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/Ref.h>
-#include <wtf/SetForScope.h>
+#include <wtf/Scope.h>
 #include <wtf/StdLibExtras.h>
 
 namespace WebCore {
@@ -91,6 +91,8 @@
     , m_createdByParser(createdByParser)
     , m_firedLoad(false)
     , m_loadedResource(false)
+    , m_isHandlingBeforeLoad(false)
+    , m_allowPrefetchLoadAndErrorForTesting(false)
     , m_pendingSheetType(Unknown)
 {
     ASSERT(hasTagName(linkTag));
@@ -298,9 +300,11 @@
         }
 
         {
-        SetForScope<bool> change(m_isHandlingBeforeLoad, true);
-        if (!shouldLoadLink())
-            return;
+            bool previous = m_isHandlingBeforeLoad;
+            m_isHandlingBeforeLoad = true;
+            makeScopeExit([&] { m_isHandlingBeforeLoad = previous; });
+            if (!shouldLoadLink())
+                return;
         }
 
         m_loading = true;
diff --git a/Source/WebCore/html/HTMLLinkElement.h b/Source/WebCore/html/HTMLLinkElement.h
index 07352a3..5a9ce0b0 100644
--- a/Source/WebCore/html/HTMLLinkElement.h
+++ b/Source/WebCore/html/HTMLLinkElement.h
@@ -118,7 +118,7 @@
 
     void finishParsingChildren() final;
 
-    enum PendingSheetType { Unknown, ActiveSheet, InactiveSheet };
+    enum PendingSheetType : uint8_t { Unknown, ActiveSheet, InactiveSheet };
     void addPendingSheet(PendingSheetType);
 
     void removePendingSheet();
@@ -127,7 +127,7 @@
     Style::Scope* m_styleScope { nullptr };
     CachedResourceHandle<CachedCSSStyleSheet> m_cachedSheet;
     RefPtr<CSSStyleSheet> m_sheet;
-    enum DisabledState {
+    enum DisabledState : uint8_t {
         Unset,
         EnabledViaScript,
         Disabled
@@ -135,20 +135,18 @@
 
     String m_type;
     String m_media;
+    String m_integrityMetadataForPendingSheetRequest;
     std::unique_ptr<DOMTokenList> m_sizes;
+    std::unique_ptr<DOMTokenList> m_relList;
     DisabledState m_disabledState;
     LinkRelAttribute m_relAttribute;
-    bool m_loading;
-    bool m_createdByParser;
-    bool m_firedLoad;
-    bool m_loadedResource;
-    bool m_isHandlingBeforeLoad { false };
-    bool m_allowPrefetchLoadAndErrorForTesting { false };
-
+    bool m_loading : 1;
+    bool m_createdByParser : 1;
+    bool m_firedLoad : 1;
+    bool m_loadedResource : 1;
+    bool m_isHandlingBeforeLoad : 1;
+    bool m_allowPrefetchLoadAndErrorForTesting : 1;
     PendingSheetType m_pendingSheetType;
-    String m_integrityMetadataForPendingSheetRequest;
-
-    std::unique_ptr<DOMTokenList> m_relList;
 };
 
 }
diff --git a/Source/WebCore/html/LinkIconCollector.h b/Source/WebCore/html/LinkIconCollector.h
index 43f22b8..78ceb8d 100644
--- a/Source/WebCore/html/LinkIconCollector.h
+++ b/Source/WebCore/html/LinkIconCollector.h
@@ -31,7 +31,7 @@
 namespace WebCore {
 
 class Document;
-enum class LinkIconType;
+enum class LinkIconType : uint8_t;
 
 class LinkIconCollector {
 public:
diff --git a/Source/WebCore/html/LinkIconType.h b/Source/WebCore/html/LinkIconType.h
index e74fd8d..bd2c4f8 100644
--- a/Source/WebCore/html/LinkIconType.h
+++ b/Source/WebCore/html/LinkIconType.h
@@ -28,8 +28,9 @@
 namespace WebCore {
 
 // These values are arranged so that they can be used with WTF::OptionSet.
+// And using it with Markable via EnumMarkableTraits.
 
-enum class LinkIconType {
+enum class LinkIconType : uint8_t {
     Favicon = 1 << 0,
     TouchIcon = 1 << 1,
     TouchPrecomposedIcon = 1 <<2
diff --git a/Source/WebCore/html/LinkRelAttribute.cpp b/Source/WebCore/html/LinkRelAttribute.cpp
index b108530..4052fa1 100644
--- a/Source/WebCore/html/LinkRelAttribute.cpp
+++ b/Source/WebCore/html/LinkRelAttribute.cpp
@@ -42,11 +42,22 @@
 namespace WebCore {
 
 LinkRelAttribute::LinkRelAttribute()
+    : iconType()
+    , isStyleSheet(false)
+    , isAlternate(false)
+    , isDNSPrefetch(false)
+    , isLinkPreload(false)
+    , isLinkPreconnect(false)
+    , isLinkPrefetch(false)
+#if ENABLE(APPLICATION_MANIFEST)
+    , isApplicationManifest(false)
+#endif
 {
 }
 
 // Keep LinkRelAttribute::isSupported() in sync when updating this constructor.
 LinkRelAttribute::LinkRelAttribute(Document& document, const String& rel)
+    : LinkRelAttribute()
 {
     if (equalLettersIgnoringASCIICase(rel, "stylesheet"))
         isStyleSheet = true;
diff --git a/Source/WebCore/html/LinkRelAttribute.h b/Source/WebCore/html/LinkRelAttribute.h
index ac1a39d..c9a478f 100644
--- a/Source/WebCore/html/LinkRelAttribute.h
+++ b/Source/WebCore/html/LinkRelAttribute.h
@@ -38,18 +38,18 @@
 namespace WebCore {
 
 class Document;
-enum class LinkIconType;
+enum class LinkIconType : uint8_t;
 
 struct LinkRelAttribute {
-    bool isStyleSheet { false };
-    Optional<LinkIconType> iconType;
-    bool isAlternate { false };
-    bool isDNSPrefetch { false };
-    bool isLinkPreload { false };
-    bool isLinkPreconnect { false };
-    bool isLinkPrefetch { false };
+    Markable<LinkIconType, EnumMarkableTraits<LinkIconType>> iconType;
+    bool isStyleSheet : 1;
+    bool isAlternate : 1;
+    bool isDNSPrefetch : 1;
+    bool isLinkPreload : 1;
+    bool isLinkPreconnect : 1;
+    bool isLinkPrefetch : 1;
 #if ENABLE(APPLICATION_MANIFEST)
-    bool isApplicationManifest { false };
+    bool isApplicationManifest : 1;
 #endif
 
     LinkRelAttribute();
diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h
index 2703747..ac330bf 100644
--- a/Source/WebCore/page/Page.h
+++ b/Source/WebCore/page/Page.h
@@ -147,7 +147,7 @@
 class WebGLStateTracker;
 class WheelEventDeltaFilter;
 
-using SharedStringHash = uint64_t;
+using SharedStringHash = uint32_t;
 
 enum class CanWrap : bool;
 enum class DidWrap : bool;
diff --git a/Source/WebCore/page/VisitedLinkStore.h b/Source/WebCore/page/VisitedLinkStore.h
index c663ba9..bfc0b90 100644
--- a/Source/WebCore/page/VisitedLinkStore.h
+++ b/Source/WebCore/page/VisitedLinkStore.h
@@ -31,7 +31,7 @@
 
 namespace WebCore {
 
-typedef uint64_t SharedStringHash;
+using SharedStringHash = uint32_t;
 class Page;
 
 class VisitedLinkStore : public RefCounted<VisitedLinkStore> {
diff --git a/Source/WebCore/platform/SharedStringHash.h b/Source/WebCore/platform/SharedStringHash.h
index 1261d77..0b25b7c 100644
--- a/Source/WebCore/platform/SharedStringHash.h
+++ b/Source/WebCore/platform/SharedStringHash.h
@@ -26,30 +26,23 @@
 #pragma once
 
 #include <wtf/Forward.h>
+#include <wtf/Markable.h>
 #include <wtf/text/StringHash.h>
 
 namespace WebCore {
 
-typedef uint64_t SharedStringHash;
+using SharedStringHash = uint32_t;
 
-// Use the low 32-bits of the 64-bit SharedStringHash as the key for HashSets.
+// This is a hash value, but it can be used as a key in HashMap. So, we need to avoid producing deleted-value in HashMap, which is -1.
 struct SharedStringHashHash {
     static unsigned hash(SharedStringHash key) { return static_cast<unsigned>(key); }
     static bool equal(SharedStringHash a, SharedStringHash b) { return a == b; }
     static const bool safeToCompareToEmptyOrDeleted = true;
-
-    // See AlreadyHashed::avoidDeletedValue.
-    static unsigned avoidDeletedValue(SharedStringHash hash64)
-    {
-        ASSERT(hash64);
-        unsigned hash = static_cast<unsigned>(hash64);
-        unsigned newHash = hash | (!(hash + 1) << 31);
-        ASSERT(newHash);
-        ASSERT(newHash != 0xFFFFFFFF);
-        return newHash;
-    }
+    static constexpr SharedStringHash deletedValue = std::numeric_limits<SharedStringHash>::max();
 };
 
+using SharedStringHashMarkableTraits = IntegralMarkableTraits<SharedStringHash, SharedStringHashHash::deletedValue>;
+
 // Returns the hash of the string that will be used for visited link coloring.
 WEBCORE_EXPORT SharedStringHash computeSharedStringHash(const String& url);
 WEBCORE_EXPORT SharedStringHash computeSharedStringHash(const UChar* url, unsigned length);