Skip to content

Commit

Permalink
Cherry-pick 50f118c. rdar://125141520
Browse files Browse the repository at this point in the history
    [WebCore] Optimize WidthCache further
    https://bugs.webkit.org/show_bug.cgi?id=270901
    rdar://124512596

    Reviewed by Ryosuke Niwa.

    This patch further optimizes WidthCache.

    1. Ensure that SmallStringKey constructor is always inlined.
    2. Add copySmallCharacters. We know that this string is <= 16, very small. Just doing for-loop is faster for this level of size.
    3. Add FloatWithZeroEmptyKeyHashTraits. float / double uses infinity for empty value. But this means that we cannot use zeroed empty value
       for HashMap<T, float> even though T's empty value is zero. We add FloatWithZeroEmptyKeyHashTraits which uses 0 for empty value, so that
       we can ensure that KeyValuePair<T, float>'s empty value is zero. Also, using character + 1 for key in SingleCharMap so that it can make
       empty value zero too.

    * Source/WTF/wtf/HashTraits.h:
    (WTF::FloatWithZeroEmptyKeyHashTraits::emptyValue):
    (WTF::FloatWithZeroEmptyKeyHashTraits::constructDeletedValue):
    (WTF::FloatWithZeroEmptyKeyHashTraits::isDeletedValue):
    * Source/WebCore/platform/graphics/WidthCache.h:
    (WebCore::WidthCache::SmallStringKey::SmallStringKey):
    (WebCore::WidthCache::SmallStringKey::copySmallCharacters):
    (WebCore::WidthCache::addSlowCase):

    Canonical link: https://commits.webkit.org/276034@main

Identifier: 272448.829@safari-7618-branch
  • Loading branch information
Constellation authored and Dan Robson committed Mar 29, 2024
1 parent f67193f commit 970aeff
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 6 deletions.
7 changes: 7 additions & 0 deletions Source/WTF/wtf/HashTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ template<typename T> struct FloatHashTraits : GenericHashTraits<T> {
static bool isDeletedValue(T value) { return value == -std::numeric_limits<T>::infinity(); }
};

template<typename T> struct FloatWithZeroEmptyKeyHashTraits : GenericHashTraits<T> {
static constexpr bool emptyValueIsZero = true;
static T emptyValue() { return static_cast<T>(0); }
static void constructDeletedValue(T& slot) { slot = -std::numeric_limits<T>::infinity(); }
static bool isDeletedValue(T value) { return value == -std::numeric_limits<T>::infinity(); }
};

template<> struct HashTraits<float> : FloatHashTraits<float> { };
template<> struct HashTraits<double> : FloatHashTraits<double> { };

Expand Down
22 changes: 16 additions & 6 deletions Source/WebCore/platform/graphics/WidthCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ class WidthCache {
{
}

SmallStringKey(StringView string)
ALWAYS_INLINE SmallStringKey(StringView string)
{
unsigned length = string.length();
ASSERT(length <= s_capacity);
if (string.is8Bit())
StringImpl::copyCharacters(m_characters.data(), string.characters8(), length);
copySmallCharacters(m_characters.data(), string.characters8(), length);
else
StringImpl::copyCharacters(m_characters.data(), string.characters16(), length);
copySmallCharacters(m_characters.data(), string.characters16(), length);
m_hashAndLength = WYHash::computeHashAndMaskTop8Bits(m_characters.data(), s_capacity) | (length << 24);
}

Expand All @@ -79,6 +79,13 @@ class WidthCache {
static constexpr unsigned s_capacity = 16;
static constexpr unsigned s_deletedValueLength = s_capacity + 1;

template<typename CharacterType>
ALWAYS_INLINE static void copySmallCharacters(UChar* dest, const CharacterType* source, unsigned length)
{
for (unsigned i = 0; i < length; ++i)
dest[i] = source[i];
}

std::array<UChar, s_capacity> m_characters { };
unsigned m_hashAndLength { 0 };
};
Expand Down Expand Up @@ -157,7 +164,10 @@ class WidthCache {
bool isNewEntry;
float* value;
if (length == 1) {
SingleCharMap::AddResult addResult = m_singleCharMap.fastAdd(text[0], entry);
// The map use 0 for empty key, thus we do +1 here to avoid conflicting against empty key.
// This is fine since the key is uint32_t while character is UChar. So +1 never causes overflow.
uint32_t character = text[0];
auto addResult = m_singleCharMap.fastAdd(character + 1, entry);
isNewEntry = addResult.isNewEntry;
value = &addResult.iterator->value;
} else {
Expand Down Expand Up @@ -186,8 +196,8 @@ class WidthCache {
return nullptr;
}

using Map = HashMap<SmallStringKey, float, SmallStringKeyHash, SmallStringKeyHashTraits>;
using SingleCharMap = HashMap<uint32_t, float, DefaultHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>>;
using Map = HashMap<SmallStringKey, float, SmallStringKeyHash, SmallStringKeyHashTraits, WTF::FloatWithZeroEmptyKeyHashTraits<float>>;
using SingleCharMap = HashMap<uint32_t, float, DefaultHash<uint32_t>, HashTraits<uint32_t>, WTF::FloatWithZeroEmptyKeyHashTraits<float>>;

static constexpr int s_minInterval = -3; // A cache hit pays for about 3 cache misses.
static constexpr int s_maxInterval = 20; // Sampling at this interval has almost no overhead.
Expand Down

0 comments on commit 970aeff

Please sign in to comment.