Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrMemoryPool.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
13
14#include <cstring>
15#include <new>
16
17#ifdef SK_DEBUG
18 #include <atomic>
19#endif
20
21///////////////////////////////////////////////////////////////////////////////////////////////////
22
23std::unique_ptr<GrMemoryPool> GrMemoryPool::Make(size_t preallocSize, size_t minAllocSize) {
24 static_assert(sizeof(GrMemoryPool) < GrMemoryPool::kMinAllocationSize);
25
28 minAllocSize = SkTPin(minAllocSize, kMinAllocationSize,
30 void* mem = operator new(preallocSize);
31 return std::unique_ptr<GrMemoryPool>(new (mem) GrMemoryPool(preallocSize, minAllocSize));
32}
33
34GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize)
35 : fAllocator(SkBlockAllocator::GrowthPolicy::kFixed, minAllocSize,
36 preallocSize - offsetof(GrMemoryPool, fAllocator) - sizeof(SkBlockAllocator)) {
38 fDebug = new Debug;
39 fDebug->fAllocationCount = 0;
40 )
41}
42
44 this->reportLeaks();
45 SkASSERT(0 == fDebug->fAllocationCount);
46 SkASSERT(this->isEmpty());
47 SkDEBUGCODE(delete fDebug;)
48}
49
51#ifdef SK_DEBUG
52 int i = 0;
53 int n = fDebug->fAllocatedIDs.count();
54 for (int id : fDebug->fAllocatedIDs) {
55 if (++i == 1) {
56 SkDebugf("Leaked %d IDs (in no particular order): %d%s", n, id, (n == i) ? "\n" : "");
57 } else if (i < 11) {
58 SkDebugf(", %d%s", id, (n == i ? "\n" : ""));
59 } else if (i == 11) {
60 SkDebugf(", ...\n");
61 break;
62 }
63 }
64#endif
65}
66
67void* GrMemoryPool::allocate(size_t size) {
68 static_assert(alignof(Header) <= kAlignment);
69 SkDEBUGCODE(this->validate();)
70
71 SkBlockAllocator::ByteRange alloc = fAllocator.allocate<kAlignment, sizeof(Header)>(size);
72
73 // Initialize GrMemoryPool's custom header at the start of the allocation
74 Header* header = static_cast<Header*>(alloc.fBlock->ptr(alloc.fAlignedOffset - sizeof(Header)));
75 header->fStart = alloc.fStart;
76 header->fEnd = alloc.fEnd;
77
78 // Update live count within the block
79 alloc.fBlock->setMetadata(alloc.fBlock->metadata() + 1);
80
81#if defined(SK_SANITIZE_ADDRESS)
82 sk_asan_poison_memory_region(&header->fSentinel, sizeof(header->fSentinel));
83#elif defined(SK_DEBUG)
84 header->fSentinel = SkBlockAllocator::kAssignedMarker;
85#endif
86
87#if defined(SK_DEBUG)
88 header->fID = []{
89 static std::atomic<int> nextID{1};
90 return nextID.fetch_add(1, std::memory_order_relaxed);
91 }();
92
93 // You can set a breakpoint here when a leaked ID is allocated to see the stack frame.
94 fDebug->fAllocatedIDs.add(header->fID);
95 fDebug->fAllocationCount++;
96#endif
97
98 // User-facing pointer is after the header padding
99 return alloc.fBlock->ptr(alloc.fAlignedOffset);
100}
101
103 Header* header = reinterpret_cast<Header*>(reinterpret_cast<intptr_t>(p) - sizeof(Header));
104
105#if defined(SK_SANITIZE_ADDRESS)
106 sk_asan_unpoison_memory_region(&header->fSentinel, sizeof(header->fSentinel));
107#elif defined(SK_DEBUG)
108 SkASSERT(SkBlockAllocator::kAssignedMarker == header->fSentinel);
109 header->fSentinel = SkBlockAllocator::kFreedMarker;
110#endif
111
112#if defined(SK_DEBUG)
113 fDebug->fAllocatedIDs.remove(header->fID);
114 fDebug->fAllocationCount--;
115#endif
116
117 SkBlockAllocator::Block* block = fAllocator.owningBlock<kAlignment>(header, header->fStart);
118
119#if defined(SK_DEBUG)
120 // (p - block) matches the original alignedOffset value from SkBlockAllocator::allocate().
121 intptr_t alignedOffset = (intptr_t)p - (intptr_t)block;
122 SkASSERT(p == block->ptr(alignedOffset));
123
124 // Scrub the block contents to prevent use-after-free errors.
125 memset(p, 0xDD, header->fEnd - alignedOffset);
126#endif
127
128 int alive = block->metadata();
129 if (alive == 1) {
130 // This was last allocation in the block, so remove it
131 fAllocator.releaseBlock(block);
132 } else {
133 // Update count and release storage of the allocation itself
134 block->setMetadata(alive - 1);
135 block->release(header->fStart, header->fEnd);
136 }
137}
138
139#ifdef SK_DEBUG
140void GrMemoryPool::validate() const {
141 fAllocator.validate();
142
143 int allocCount = 0;
144 for (const auto* b : fAllocator.blocks()) {
145 allocCount += b->metadata();
146 }
147 SkASSERT(allocCount == fDebug->fAllocationCount);
148 SkASSERT(fDebug->fAllocationCount == fDebug->fAllocatedIDs.count());
149 SkASSERT(allocCount > 0 || this->isEmpty());
150}
151#endif
static void sk_asan_poison_memory_region(void const volatile *addr, size_t size)
Definition SkASAN.h:34
static void sk_asan_unpoison_memory_region(void const volatile *addr, size_t size)
Definition SkASAN.h:41
#define SkASSERT(cond)
Definition SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition SkTPin.h:19
void * allocate(size_t size)
static constexpr size_t kAlignment
static std::unique_ptr< GrMemoryPool > Make(size_t preallocSize, size_t minAllocSize)
static constexpr size_t kMinAllocationSize
void reportLeaks() const
size_t size() const
size_t preallocSize() const
bool isEmpty() const
void release(void *p)
bool release(int start, int end)
void * ptr(int offset)
void setMetadata(int value)
void releaseBlock(Block *block)
ByteRange allocate(size_t size)
static constexpr int kMaxAllocationSize
Block * owningBlock(const void *ptr, int start)
static bool b
static const char header[]
Definition skpbench.cpp:88