diff --git a/src/sksl/SkSLExternalValue.h b/src/sksl/SkSLExternalValue.h index cd2c09a2d7..aac27ca38c 100644 --- a/src/sksl/SkSLExternalValue.h +++ b/src/sksl/SkSLExternalValue.h @@ -105,6 +105,17 @@ public: return String("external<") + this->name() + ">"; } + // Disable IRNode pooling on external value nodes. ExternalValue node lifetimes are controlled + // by the calling code; we can't guarantee that they will be destroyed before a Program is + // freed. (In fact, it's very unlikely that they would be.) + static void* operator new(const size_t size) { + return ::operator new(size); + } + + static void operator delete(void* ptr) { + ::operator delete(ptr); + } + private: using INHERITED = Symbol; diff --git a/src/sksl/SkSLPool.cpp b/src/sksl/SkSLPool.cpp index fcf04076f2..8263bbbf93 100644 --- a/src/sksl/SkSLPool.cpp +++ b/src/sksl/SkSLPool.cpp @@ -14,9 +14,12 @@ namespace SkSL { +static constexpr int kSmallNodeSize = 120; +static constexpr int kNodesInPool = 512; + namespace { struct IRNodeData { union { - uint8_t fBuffer[sizeof(IRNode)]; + uint8_t fBuffer[kSmallNodeSize]; IRNodeData* fFreeListNext; }; }; } @@ -116,8 +119,6 @@ Pool::~Pool() { } std::unique_ptr Pool::Create() { - constexpr int kNodesInPool = 512; - SkAutoMutexExclusive lock(recycled_pool_mutex()); std::unique_ptr pool; if (sRecycledPool) { @@ -159,23 +160,26 @@ void Pool::detachFromThread() { set_thread_local_pool_data(nullptr); } -void* Pool::AllocIRNode() { +void* Pool::AllocIRNode(size_t size) { // Is a pool attached? PoolData* poolData = get_thread_local_pool_data(); if (poolData) { - // Does the pool contain a free node? - IRNodeData* node = poolData->fFreeListHead; - if (node) { - // Yes. Take a node from the freelist. - poolData->fFreeListHead = node->fFreeListNext; - VLOG("ALLOC Pool:0x%016llX Index:%04d 0x%016llX\n", - (uint64_t)poolData, poolData->nodeIndex(node), (uint64_t)node); - return node->fBuffer; + // Can the requested size fit in a pool node? + if (size <= kSmallNodeSize) { + // Does the pool contain a free node? + IRNodeData* node = poolData->fFreeListHead; + if (node) { + // Yes. Take a node from the freelist. + poolData->fFreeListHead = node->fFreeListNext; + VLOG("ALLOC Pool:0x%016llX Index:%04d 0x%016llX\n", + (uint64_t)poolData, poolData->nodeIndex(node), (uint64_t)node); + return node->fBuffer; + } } } - // The pool is detached or full; allocate nodes using malloc. - void* ptr = ::operator new(sizeof(IRNode)); + // The pool can't be used for this allocation. Allocate nodes using the system allocator. + void* ptr = ::operator new(size); VLOG("ALLOC Pool:0x%016llX Index:____ malloc 0x%016llX\n", (uint64_t)poolData, (uint64_t)ptr); return ptr; @@ -197,7 +201,7 @@ void Pool::FreeIRNode(void* node_v) { } } - // No pool is attached or the node was malloced; it must be freed. + // We couldn't associate this node with our pool. Free it using the system allocator. VLOG("FREE Pool:0x%016llX Index:____ free 0x%016llX\n", (uint64_t)poolData, (uint64_t)node_v); ::operator delete(node_v); diff --git a/src/sksl/SkSLPool.h b/src/sksl/SkSLPool.h index 2933fd0279..69da9a133e 100644 --- a/src/sksl/SkSLPool.h +++ b/src/sksl/SkSLPool.h @@ -41,8 +41,9 @@ public: // It is an error to call this while no pool is attached. void detachFromThread(); - // Retrieves a node from the thread pool. If the pool is exhausted, this will allocate a node. - static void* AllocIRNode(); + // Retrieves a node from the thread pool. If the pool is exhausted, or if the requested size + // exceeds the size that we can deliver from a pool, this will just allocate memory. + static void* AllocIRNode(size_t size); // Releases a node that was created by AllocIRNode. This will return it to the pool, or free it, // as appropriate. Make sure to free all nodes, since some of them may be real allocations. diff --git a/src/sksl/ir/SkSLIRNode.h b/src/sksl/ir/SkSLIRNode.h index 7a26e4cf9a..060113afcf 100644 --- a/src/sksl/ir/SkSLIRNode.h +++ b/src/sksl/ir/SkSLIRNode.h @@ -67,10 +67,7 @@ public: // Override operator new and delete to allow us to control allocation behavior. static void* operator new(const size_t size) { - if (size == sizeof(IRNode)) { - return Pool::AllocIRNode(); - } - return ::operator new(size); + return Pool::AllocIRNode(size); } static void operator delete(void* ptr) {