Bug 1762713 - Move work of InitWordCache inside of GetShapedWord to avoid extra lock-twiddling. r=lsalzman

No behavior change, but this reduces lock-management overhead.

Differential Revision: https://phabricator.services.mozilla.com/D142752
This commit is contained in:
Jonathan Kew 2022-04-02 15:52:04 +00:00
parent a2098c0b7d
commit 9cea60e6b9
3 changed files with 38 additions and 52 deletions

View File

@ -2829,42 +2829,30 @@ gfxShapedWord* gfxFont::GetShapedWord(
Script aRunScript, nsAtom* aLanguage, bool aVertical,
int32_t aAppUnitsPerDevUnit, gfx::ShapedTextFlags aFlags,
RoundingFlags aRounding, gfxTextPerfMetrics* aTextPerf GFX_MAYBE_UNUSED) {
// if the cache is getting too big, flush it and start over
uint32_t wordCacheMaxEntries =
gfxPlatform::GetPlatform()->WordCacheMaxEntries();
mLock.ReadLock();
if (mWordCache->Count() > wordCacheMaxEntries) {
// Flush the cache if it is getting overly big.
// There's a chance another thread could race with the lock-twiddling here,
// but that's OK; it's harmless if we end up calling ClearCacheWords twice
// from separate threads. Internally, it will hold the lock exclusively
// while doing its thing.
mLock.ReadUnlock();
NS_WARNING("flushing shaped-word cache");
ClearCachedWords();
mLock.ReadLock();
// Once we've reclaimed a read lock, we can proceed knowing the cache
// isn't growing uncontrollably.
}
// if there's a cached entry for this word, just return it
CacheHashKey key(aText, aLength, aHash, aRunScript, aLanguage,
aAppUnitsPerDevUnit, aFlags, aRounding);
CacheHashEntry* entry = mWordCache->GetEntry(key);
if (entry) {
gfxShapedWord* sw = entry->mShapedWord.get();
sw->ResetAge();
{
// If we have a word cache, attempt to look up the word in it.
AutoReadLock lock(mLock);
if (mWordCache) {
// if there's a cached entry for this word, just return it
if (CacheHashEntry* entry = mWordCache->GetEntry(key)) {
gfxShapedWord* sw = entry->mShapedWord.get();
sw->ResetAge();
#ifndef RELEASE_OR_BETA
if (aTextPerf) {
// XXX we should make sure this is atomic
aTextPerf->current.wordCacheHit++;
}
if (aTextPerf) {
// XXX we should make sure this is atomic
aTextPerf->current.wordCacheHit++;
}
#endif
mLock.ReadUnlock();
return sw;
return sw;
}
}
}
mLock.ReadUnlock();
// We didn't find a cached word (or don't even have a cache yet), so create
// a new gfxShapedWord and cache it. We don't have to lock during shaping,
// only when it comes time to cache the new entry.
gfxShapedWord* sw =
gfxShapedWord::Create(aText, aLength, aRunScript, aLanguage,
@ -2878,9 +2866,21 @@ gfxShapedWord* gfxFont::GetShapedWord(
NS_WARNING_ASSERTION(ok, "failed to shape word - expect garbled text");
{
// We're going to cache the new shaped word, so lock for writing.
// We're going to cache the new shaped word, so lock for writing now.
AutoWriteLock lock(mLock);
entry = mWordCache->PutEntry(key, fallible);
if (!mWordCache) {
mWordCache = MakeUnique<nsTHashtable<CacheHashEntry>>();
} else {
// If the cache is getting too big, flush it and start over.
uint32_t wordCacheMaxEntries =
gfxPlatform::GetPlatform()->WordCacheMaxEntries();
if (mWordCache->Count() > wordCacheMaxEntries) {
// Flush the cache if it is getting overly big.
NS_WARNING("flushing shaped-word cache");
ClearCachedWordsLocked();
}
}
CacheHashEntry* entry = mWordCache->PutEntry(key, fallible);
if (!entry) {
NS_WARNING("failed to create word cache entry - expect missing text");
delete sw;
@ -3240,8 +3240,6 @@ bool gfxFont::SplitAndInitTextRun(
}
}
InitWordCache();
// the only flags we care about for ShapedWord construction/caching
gfx::ShapedTextFlags flags = aTextRun->GetFlags();
flags &= (gfx::ShapedTextFlags::TEXT_IS_RTL |

View File

@ -1877,21 +1877,6 @@ class gfxFont {
RoundingFlags aRounding,
gfxTextPerfMetrics* aTextPerf);
// Ensure the ShapedWord cache is initialized. This MUST be called before
// any attempt to use GetShapedWord().
void InitWordCache() {
mLock.ReadLock();
if (!mWordCache) {
mLock.ReadUnlock();
mozilla::AutoWriteLock lock(mLock);
if (!mWordCache) {
mWordCache = mozilla::MakeUnique<nsTHashtable<CacheHashEntry>>();
}
} else {
mLock.ReadUnlock();
}
}
// Called by the gfxFontCache timer to increment the age of all the words,
// so that they'll expire after a sufficient period of non-use.
// Returns true if the cache is now empty, otherwise false.
@ -1901,9 +1886,13 @@ class gfxFont {
void ClearCachedWords() {
mozilla::AutoWriteLock lock(mLock);
if (mWordCache) {
mWordCache->Clear();
ClearCachedWordsLocked();
}
}
void ClearCachedWordsLocked() REQUIRES(mLock) {
MOZ_ASSERT(mWordCache);
mWordCache->Clear();
}
// Glyph rendering/geometry has changed, so invalidate data as necessary.
void NotifyGlyphsChanged() const;

View File

@ -1548,7 +1548,6 @@ void gfxTextRun::SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
return;
}
aFont->InitWordCache();
static const uint8_t space = ' ';
gfx::ShapedTextFlags flags =
gfx::ShapedTextFlags::TEXT_IS_8BIT | aOrientation;