Revert "Multi-threaded strike cache"

This reverts commit a6cd7c0b1f989840efe203979943cbb59d4d131b.

Reason for revert: Introduced nullptr de-ref in last patch

Original change's description:
> Multi-threaded strike cache
> 
> Allow multiple threads to share the same strike. The old
> system of removing the cache from the linked list is no longer.
> The strikes stay in the list and can be found by other threads.
> 
> * Removed strike size verification. There was no way to get the
> locks to work out. The whole point of the change was to have multiple
> threads muting the structure at the same time.
> 
> * Strikes are now refed instead of being checked out. Therefore,
> ExclusiveStrikePtr is now just wraps an sk_sp, and should be renamed
> in a future CL.
> 
> Change-Id: I832642332a3106e30745f9cdd3156ae72d41fd0b
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/272057
> Reviewed-by: Ben Wagner <bungeman@google.com>
> Commit-Queue: Herb Derby <herb@google.com>

TBR=bungeman@google.com,herb@google.com

Change-Id: Ie1acd9b42e614c17cb63bda1b3fd4dd9827a8fa6
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/272378
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/core/SkScalerCache.cpp b/src/core/SkScalerCache.cpp
index 5cc69cc..7e8741a 100644
--- a/src/core/SkScalerCache.cpp
+++ b/src/core/SkScalerCache.cpp
@@ -237,7 +237,6 @@
 
 void SkScalerCache::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
         SkGlyph* glyph, SkScalar* array, int* count) {
-    SkAutoMutexExclusive lock{fMu};
     glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
 }
 
@@ -259,3 +258,21 @@
     SkDebugf("%s\n", msg.c_str());
 }
 
+#ifdef SK_DEBUG
+size_t SkScalerCache::recalculateMemoryUsed() const {
+    SkAutoMutexExclusive lock{fMu};
+    size_t memoryUsed = sizeof(*this);
+    fGlyphMap.foreach ([&memoryUsed](const SkGlyph* glyphPtr) {
+        memoryUsed += sizeof(SkGlyph);
+        if (glyphPtr->setImageHasBeenCalled()) {
+            memoryUsed += glyphPtr->imageSize();
+        }
+        if (glyphPtr->setPathHasBeenCalled() && glyphPtr->path() != nullptr) {
+            memoryUsed += glyphPtr->path()->approximateBytesUsed();
+        }
+    });
+    return memoryUsed;
+}
+#endif  // SK_DEBUG
+
+
diff --git a/src/core/SkScalerCache.h b/src/core/SkScalerCache.h
index 4d4496c..68b202b 100644
--- a/src/core/SkScalerCache.h
+++ b/src/core/SkScalerCache.h
@@ -85,6 +85,10 @@
 
     SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
 
+#ifdef SK_DEBUG
+    size_t recalculateMemoryUsed() const SK_EXCLUDES(fMu);
+#endif
+
 private:
     class GlyphMapHashTraits {
     public:
diff --git a/src/core/SkStrikeCache.cpp b/src/core/SkStrikeCache.cpp
index fe40da2..51d40c2 100644
--- a/src/core/SkStrikeCache.cpp
+++ b/src/core/SkStrikeCache.cpp
@@ -31,25 +31,35 @@
     return cache;
 }
 
-SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(sk_sp<Strike> strike)
-    : fStrike{std::move(strike)} {}
+SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(SkStrikeCache::Strike* strike)
+    : fStrike{strike} {}
 
 SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr()
     : fStrike{nullptr} {}
 
 SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(ExclusiveStrikePtr&& o)
-    : fStrike{std::move(o.fStrike)} {
+    : fStrike{o.fStrike} {
     o.fStrike = nullptr;
 }
 
 SkStrikeCache::ExclusiveStrikePtr&
-SkStrikeCache::ExclusiveStrikePtr::operator = (ExclusiveStrikePtr&& that) {
-    fStrike = std::move(that.fStrike);
+SkStrikeCache::ExclusiveStrikePtr::operator = (ExclusiveStrikePtr&& o) {
+    if (fStrike != nullptr) {
+        fStrike->fStrikeCache->attachStrike(fStrike);
+    }
+    fStrike = o.fStrike;
+    o.fStrike = nullptr;
     return *this;
 }
 
+SkStrikeCache::ExclusiveStrikePtr::~ExclusiveStrikePtr() {
+    if (fStrike != nullptr) {
+        fStrike->fStrikeCache->attachStrike(fStrike);
+    }
+}
+
 SkStrike* SkStrikeCache::ExclusiveStrikePtr::get() const {
-    return fStrike.get();
+    return fStrike;
 }
 
 SkStrike* SkStrikeCache::ExclusiveStrikePtr::operator -> () const {
@@ -94,8 +104,8 @@
 
 auto SkStrikeCache::findOrCreateStrike(const SkDescriptor& desc,
                                        const SkScalerContextEffects& effects,
-                                       const SkTypeface& typeface) -> sk_sp<Strike> {
-    sk_sp<Strike> strike = this->findStrikeOrNull(desc);
+                                       const SkTypeface& typeface) -> Strike* {
+    Strike* strike = this->findAndDetachStrike(desc);
     if (strike == nullptr) {
         auto scaler = typeface.createScalerContext(effects, &desc);
         strike = this->createStrike(desc, std::move(scaler));
@@ -106,7 +116,7 @@
 SkScopedStrikeForGPU SkStrikeCache::findOrCreateScopedStrike(const SkDescriptor& desc,
                                                              const SkScalerContextEffects& effects,
                                                              const SkTypeface& typeface) {
-    return SkScopedStrikeForGPU{this->findOrCreateStrike(desc, effects, typeface).release()};
+    return SkScopedStrikeForGPU{this->findOrCreateStrike(desc, effects, typeface)};
 }
 
 void SkStrikeCache::PurgeAll() {
@@ -178,30 +188,30 @@
     GlobalStrikeCache()->forEachStrike(visitor);
 }
 
-SkExclusiveStrikePtr SkStrikeCache::findStrikeExclusive(const SkDescriptor& desc) {
-    return SkExclusiveStrikePtr(this->findStrikeOrNull(desc));
+
+void SkStrikeCache::attachStrike(Strike* strike) {
+    if (strike == nullptr) {
+        return;
+    }
+    SkAutoSpinlock ac(fLock);
+
+    this->validate();
+
+    this->internalAttachToHead(strike);
+    this->internalPurge();
 }
 
-auto SkStrikeCache::findStrikeOrNull(const SkDescriptor& desc) -> sk_sp<Strike> {
+SkExclusiveStrikePtr SkStrikeCache::findStrikeExclusive(const SkDescriptor& desc) {
+    return SkExclusiveStrikePtr(this->findAndDetachStrike(desc));
+}
+
+auto SkStrikeCache::findAndDetachStrike(const SkDescriptor& desc) -> Strike* {
     SkAutoSpinlock ac(fLock);
 
     for (Strike* strike = fHead; strike != nullptr; strike = strike->fNext) {
         if (strike->fScalerCache.getDescriptor() == desc) {
-            if (fHead != strike) {
-                // Make most recently used
-                strike->fPrev->fNext = strike->fNext;
-                if (strike->fNext != nullptr) {
-                    strike->fNext->fPrev = strike->fPrev;
-                } else {
-                    fTail = strike->fPrev;
-                }
-                fHead->fPrev = strike;
-                strike->fNext = fHead;
-                strike->fPrev = nullptr;
-                fHead = strike;
-            }
-
-            return sk_ref_sp(strike);
+            this->internalDetachStrike(strike);
+            return strike;
         }
     }
 
@@ -222,12 +232,8 @@
         const SkDescriptor& desc,
         std::unique_ptr<SkScalerContext> scaler,
         SkFontMetrics* maybeMetrics,
-        std::unique_ptr<SkStrikePinner> pinner) -> sk_sp<Strike> {
-    auto strike =
-            sk_make_sp<Strike>(this, desc, std::move(scaler), maybeMetrics, std::move(pinner));
-    SkAutoSpinlock lock{fLock};
-    this->internalAttachToHead(strike);
-    return strike;
+        std::unique_ptr<SkStrikePinner> pinner) -> Strike* {
+    return new Strike{this, desc, std::move(scaler), maybeMetrics, std::move(pinner)};
 }
 
 void SkStrikeCache::purgeAll() {
@@ -347,7 +353,8 @@
         if (strike->fPinner == nullptr || strike->fPinner->canDelete()) {
             bytesFreed += strike->fMemoryUsed;
             countFreed += 1;
-            this->internalRemoveStrike(strike);
+            this->internalDetachStrike(strike);
+            strike->unref();
         }
         strike = prev;
     }
@@ -364,25 +371,23 @@
     return bytesFreed;
 }
 
-void SkStrikeCache::internalAttachToHead(sk_sp<Strike> strike) {
+void SkStrikeCache::internalAttachToHead(Strike* strike) {
     SkASSERT(nullptr == strike->fPrev && nullptr == strike->fNext);
+    if (fHead) {
+        fHead->fPrev = strike;
+        strike->fNext = fHead;
+    }
+    fHead = strike;
+
+    if (fTail == nullptr) {
+        fTail = strike;
+    }
 
     fCacheCount += 1;
     fTotalMemoryUsed += strike->fMemoryUsed;
-
-    if (fHead) {
-        fHead->fPrev = strike.get();
-        strike->fNext = fHead;
-    }
-
-    if (fTail == nullptr) {
-        fTail = strike.get();
-    }
-
-    fHead = strike.release(); // Transfer ownership of strike to the cache list.
 }
 
-void SkStrikeCache::internalRemoveStrike(Strike* strike) {
+void SkStrikeCache::internalDetachStrike(Strike* strike) {
     SkASSERT(fCacheCount > 0);
     fCacheCount -= 1;
     fTotalMemoryUsed -= strike->fMemoryUsed;
@@ -398,10 +403,23 @@
         fTail = strike->fPrev;
     }
     strike->fPrev = strike->fNext = nullptr;
-    strike->fStrikeCache = nullptr;
-    strike->unref();
 }
 
+void SkStrikeCache::ValidateGlyphCacheDataSize() {
+#ifdef SK_DEBUG
+    GlobalStrikeCache()->validateGlyphCacheDataSize();
+#endif
+}
+
+#ifdef SK_DEBUG
+void SkStrikeCache::validateGlyphCacheDataSize() const {
+    this->forEachStrike(
+            [](const Strike& strike) {
+                SkASSERT(strike.fMemoryUsed == strike.fScalerCache.recalculateMemoryUsed());
+            });
+}
+#endif
+
 #ifdef SK_DEBUG
 void SkStrikeCache::validate() const {
     size_t computedBytes = 0;
diff --git a/src/core/SkStrikeCache.h b/src/core/SkStrikeCache.h
index 089e164..8a273a5 100644
--- a/src/core/SkStrikeCache.h
+++ b/src/core/SkStrikeCache.h
@@ -55,14 +55,16 @@
                 , fPinner{std::move(pinner)} {}
 
         SkGlyph* mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from) {
-            auto [glyph, increase] = fScalerCache.mergeGlyphAndImage(toID, from);
-            this->updateDelta(increase);
+            auto [glyph, delta] = fScalerCache.mergeGlyphAndImage(toID, from);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
             return glyph;
         }
 
         const SkPath* mergePath(SkGlyph* glyph, const SkPath* path) {
-            auto [glyphPath, increase] = fScalerCache.mergePath(glyph, path);
-            this->updateDelta(increase);
+            auto [glyphPath, delta] = fScalerCache.mergePath(glyph, path);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
             return glyphPath;
         }
 
@@ -81,28 +83,32 @@
 
         SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID> glyphIDs,
                                        const SkGlyph* results[]) {
-            auto [glyphs, increase] = fScalerCache.metrics(glyphIDs, results);
-            this->updateDelta(increase);
+            auto [glyphs, delta] = fScalerCache.metrics(glyphIDs, results);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
             return glyphs;
         }
 
         SkSpan<const SkGlyph*> preparePaths(SkSpan<const SkGlyphID> glyphIDs,
                                             const SkGlyph* results[]) {
-            auto [glyphs, increase] = fScalerCache.preparePaths(glyphIDs, results);
-            this->updateDelta(increase);
+            auto [glyphs, delta] = fScalerCache.preparePaths(glyphIDs, results);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
             return glyphs;
         }
 
         SkSpan<const SkGlyph*> prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,
                                              const SkGlyph* results[]) {
-            auto [glyphs, increase] = fScalerCache.prepareImages(glyphIDs, results);
-            this->updateDelta(increase);
+            auto [glyphs, delta] = fScalerCache.prepareImages(glyphIDs, results);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
             return glyphs;
         }
 
         void prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) {
-            size_t increase = fScalerCache.prepareForDrawingMasksCPU(drawables);
-            this->updateDelta(increase);
+            size_t delta = fScalerCache.prepareForDrawingMasksCPU(drawables);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
         }
 
         const SkGlyphPositionRoundingSpec& roundingSpec() const override {
@@ -115,37 +121,30 @@
 
         void prepareForMaskDrawing(
                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
-            size_t increase = fScalerCache.prepareForMaskDrawing(drawbles, rejects);
-            this->updateDelta(increase);
+            size_t delta = fScalerCache.prepareForMaskDrawing(drawbles, rejects);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
         }
 
         void prepareForSDFTDrawing(
                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
-            size_t increase = fScalerCache.prepareForSDFTDrawing(drawbles, rejects);
-            this->updateDelta(increase);
+            size_t delta = fScalerCache.prepareForSDFTDrawing(drawbles, rejects);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
         }
 
         void prepareForPathDrawing(
                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
-            size_t increase = fScalerCache.prepareForPathDrawing(drawbles, rejects);
-            this->updateDelta(increase);
+            size_t delta = fScalerCache.prepareForPathDrawing(drawbles, rejects);
+            fMemoryUsed += delta;
+            SkASSERT(fScalerCache.recalculateMemoryUsed() == fMemoryUsed);
         }
 
         void onAboutToExitScope() override {
-            this->unref();
+            fStrikeCache->attachStrike(this);
         }
 
-        void updateDelta(size_t increase) {
-            if (increase != 0) {
-                SkAutoSpinlock lock{fStrikeCache->fLock};
-                fMemoryUsed += increase;
-                if (fStrikeCache != nullptr) {
-                    fStrikeCache->fTotalMemoryUsed += increase;
-                }
-            }
-        }
-
-        SkStrikeCache*                  fStrikeCache{nullptr};
+        SkStrikeCache* const            fStrikeCache;
         Strike*                         fNext{nullptr};
         Strike*                         fPrev{nullptr};
         SkScalerCache                   fScalerCache;
@@ -155,12 +154,13 @@
 
     class ExclusiveStrikePtr {
     public:
-        explicit ExclusiveStrikePtr(sk_sp<Strike> strike);
+        explicit ExclusiveStrikePtr(Strike*);
         ExclusiveStrikePtr();
         ExclusiveStrikePtr(const ExclusiveStrikePtr&) = delete;
         ExclusiveStrikePtr& operator = (const ExclusiveStrikePtr&) = delete;
         ExclusiveStrikePtr(ExclusiveStrikePtr&&);
         ExclusiveStrikePtr& operator = (ExclusiveStrikePtr&&);
+        ~ExclusiveStrikePtr();
 
         Strike* get() const;
         Strike* operator -> () const;
@@ -171,7 +171,7 @@
         friend bool operator == (decltype(nullptr), const ExclusiveStrikePtr&);
 
     private:
-        sk_sp<Strike> fStrike;
+        Strike* fStrike;
     };
 
     static SkStrikeCache* GlobalStrikeCache();
@@ -194,6 +194,7 @@
                                                   const SkTypeface& typeface) override;
 
     static void PurgeAll();
+    static void ValidateGlyphCacheDataSize();
     static void Dump();
 
     // Dump memory usage statistics of all the attaches caches in the process using the
@@ -212,6 +213,12 @@
 
     int  getCachePointSizeLimit() const;
     int  setCachePointSizeLimit(int limit);
+#ifdef SK_DEBUG
+    // Make sure that each glyph cache's memory tracking and actual memory used are in sync.
+    void validateGlyphCacheDataSize() const;
+#else
+    void validateGlyphCacheDataSize() const {}
+#endif
 
 private:
 #ifdef SK_DEBUG
@@ -221,20 +228,21 @@
     void validate() const {}
 #endif
 
-    sk_sp<Strike> findStrikeOrNull(const SkDescriptor& desc) SK_EXCLUDES(fLock);
-    sk_sp<Strike> createStrike(
+    Strike* findAndDetachStrike(const SkDescriptor&) SK_EXCLUDES(fLock);
+    Strike* createStrike(
             const SkDescriptor& desc,
             std::unique_ptr<SkScalerContext> scaler,
             SkFontMetrics* maybeMetrics = nullptr,
-            std::unique_ptr<SkStrikePinner> = nullptr) SK_EXCLUDES(fLock);
-    sk_sp<Strike> findOrCreateStrike(
+            std::unique_ptr<SkStrikePinner> = nullptr);
+    Strike* findOrCreateStrike(
             const SkDescriptor& desc,
             const SkScalerContextEffects& effects,
             const SkTypeface& typeface) SK_EXCLUDES(fLock);
+    void attachStrike(Strike* strike) SK_EXCLUDES(fLock);
 
     // The following methods can only be called when mutex is already held.
-    void internalRemoveStrike(Strike* strike) SK_REQUIRES(fLock);
-    void internalAttachToHead(sk_sp<Strike> strike) SK_REQUIRES(fLock);
+    void internalDetachStrike(Strike* strike) SK_REQUIRES(fLock);
+    void internalAttachToHead(Strike* strike) SK_REQUIRES(fLock);
 
     // Checkout budgets, modulated by the specified min-bytes-needed-to-purge,
     // and attempt to purge caches to match.
diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp
index 1b870aa..96f94d7 100644
--- a/tests/SkRemoteGlyphCacheTest.cpp
+++ b/tests/SkRemoteGlyphCacheTest.cpp
@@ -403,6 +403,7 @@
     // Client.
     REPORTER_ASSERT(reporter,
                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
+    SkStrikeCache::ValidateGlyphCacheDataSize();
 
     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
     discardableManager->unlockAndDeleteAll();
@@ -486,6 +487,7 @@
     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
     compare_blobs(expected, actual, reporter, 1);
     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
+    SkStrikeCache::ValidateGlyphCacheDataSize();
 
     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
     discardableManager->unlockAndDeleteAll();
@@ -562,6 +564,7 @@
     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
     compare_blobs(expected, actual, reporter);
     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
+    SkStrikeCache::ValidateGlyphCacheDataSize();
 
     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
     discardableManager->unlockAndDeleteAll();
@@ -636,6 +639,7 @@
     // interpolation.
     compare_blobs(expected, actual, reporter, 36);
     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
+    SkStrikeCache::ValidateGlyphCacheDataSize();
 
     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
     discardableManager->unlockAndDeleteAll();
@@ -673,6 +677,7 @@
     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
     compare_blobs(expected, actual, reporter);
     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
+    SkStrikeCache::ValidateGlyphCacheDataSize();
 
     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
     discardableManager->unlockAndDeleteAll();
@@ -718,6 +723,7 @@
     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
     compare_blobs(expected, actual, reporter);
     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
+    SkStrikeCache::ValidateGlyphCacheDataSize();
 
     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
     discardableManager->unlockAndDeleteAll();
@@ -807,6 +813,7 @@
 
         RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
         REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
+        SkStrikeCache::ValidateGlyphCacheDataSize();
         discardableManager->resetCacheMissCounts();
     }