Allow SkSL compilers to reuse SkSL Pools without reallocating.

When a Program is freed, rather than immediately disposing of its Pool,
it now sends it to Pool::Recycle, which holds onto it. If Pool::Create
is called, it satisfies the request by simply handing back the recycled
pool. Only one pool is kept in recycle storage at a time--recycling
more than one pool in a row will cause all but one to be freed. To avoid
holding onto Pool memory indefinitely, pool recycle storage is cleaned
up whenever a Compiler is destroyed.

Change-Id: I21c1ccde84507e344102d05506d869e62ca095a6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/329175
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/SkSLPool.h b/src/sksl/SkSLPool.h
index f7338ac..2933fd0 100644
--- a/src/sksl/SkSLPool.h
+++ b/src/sksl/SkSLPool.h
@@ -19,21 +19,28 @@
 public:
     ~Pool();
 
-    // Creates a pool to store newly-created IRNodes during program creation and attaches it to the
-    // current thread. When your program is complete, call pool->detachFromThread() to transfer
-    // ownership of those nodes. Before destroying any of the program's nodes, reattach the pool via
-    // pool->attachToThread(). It is an error to call CreatePoolOnThread if a pool is already
-    // attached to the current thread.
-    static std::unique_ptr<Pool> CreatePoolOnThread(int nodesInPool);
+    // Creates a pool to store IRNodes during program creation. Call attachToThread() to start using
+    // the pool for IRNode allocations. When your program is complete, call pool->detachFromThread()
+    // to take ownership of the pool and its nodes. Before destroying any of the program's nodes,
+    // make sure to reattach the pool by calling pool->attachToThread() again.
+    static std::unique_ptr<Pool> Create();
 
-    // Once a pool has been created and the ephemeral work has completed, detach it from its thread.
+    // Gives up ownership of a pool; conceptually, this deletes it. In practice, on some platforms,
+    // it is expensive to free and reallocate pools, so this gives us an opportunity to reuse the
+    // allocation for future CreatePoolOnThread calls.
+    static void Recycle(std::unique_ptr<Pool> pool);
+
+    // Explicitly frees a previously recycled pool (if any), reclaiming the memory.
+    static void FreeRecycledPool() { Recycle(nullptr); }
+
+    // Attaches a pool to the current thread.
+    // It is an error to call this while a pool is already attached.
+    void attachToThread();
+
+    // Once you are done creating or destroying IRNodes in the pool, detach it from the thread.
     // It is an error to call this while no pool is attached.
     void detachFromThread();
 
-    // Reattaches a pool to the current thread. It is an error to call this while a pool is already
-    // attached.
-    void attachToThread();
-
     // Retrieves a node from the thread pool. If the pool is exhausted, this will allocate a node.
     static void* AllocIRNode();
 
@@ -42,6 +49,8 @@
     static void FreeIRNode(void* node_v);
 
 private:
+    void checkForLeaks();
+
     Pool() = default;  // use CreatePoolOnThread to make a pool
     PoolData* fData = nullptr;
 };