Flutter Engine
The Flutter Engine
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
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
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
void * allocate(size_t size)
static constexpr size_t kAlignment
Definition: GrMemoryPool.h:40
static std::unique_ptr< GrMemoryPool > Make(size_t preallocSize, size_t minAllocSize)
static constexpr size_t kMinAllocationSize
Definition: GrMemoryPool.h:44
void reportLeaks() const
size_t size() const
Definition: GrMemoryPool.h:90
size_t preallocSize() const
Definition: GrMemoryPool.h:95
bool isEmpty() const
Definition: GrMemoryPool.h:73
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
BlockIter< true, false > blocks()
Block * owningBlock(const void *ptr, int start)
static bool b
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
static const char header[]
Definition: skpbench.cpp:88