• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #ifndef GrMemoryPool_DEFINED
9 #define GrMemoryPool_DEFINED
10 
11 #include "src/base/SkBlockAllocator.h"
12 
13 #include <cstddef>
14 #include <cstdint>
15 #include <memory>
16 #include <type_traits>
17 
18 #ifdef SK_DEBUG
19 #include "src/core/SkTHash.h"
20 #endif
21 
22 /**
23  * Allocates memory in blocks and parcels out space in the blocks for allocation requests. It is
24  * optimized for allocate / release speed over memory efficiency. The interface is designed to be
25  * used to implement operator new and delete overrides. All allocations are expected to be released
26  * before the pool's destructor is called. Allocations will be aligned to sizeof(std::max_align_t).
27  *
28  * All allocated objects must be released back to the memory pool before it can be destroyed.
29  */
30 class GrMemoryPool {
31 public:
32 #ifdef SK_FORCE_8_BYTE_ALIGNMENT
33     // https://github.com/emscripten-core/emscripten/issues/10072
34     // Since Skia does not use "long double" (16 bytes), we should be ok to force it back to 8 bytes
35     // until emscripten is fixed.
36     inline static constexpr size_t kAlignment = 8;
37 #else
38     // Guaranteed alignment of pointer returned by allocate().
39     inline static constexpr size_t kAlignment = alignof(std::max_align_t);
40 #endif
41 
42     // Smallest block size allocated on the heap (not the smallest reservation via allocate()).
43     inline static constexpr size_t kMinAllocationSize = 1 << 10;
44 
45     /**
46      * Prealloc size is the amount of space to allocate at pool creation
47      * time and keep around until pool destruction. The min alloc size is
48      * the smallest allowed size of additional allocations. Both sizes are
49      * adjusted to ensure that they are at least as large as kMinAllocationSize
50      * and less than SkBlockAllocator::kMaxAllocationSize.
51      *
52      * Both sizes are what the pool will end up allocating from the system, and
53      * portions of the allocated memory is used for internal bookkeeping.
54      */
55     static std::unique_ptr<GrMemoryPool> Make(size_t preallocSize, size_t minAllocSize);
56 
57     ~GrMemoryPool();
delete(void * p)58     void operator delete(void* p) { ::operator delete(p); }
59 
60     /**
61      * Allocates memory. The memory must be freed with release() before the GrMemoryPool is deleted.
62      */
63     void* allocate(size_t size);
64     /**
65      * p must have been returned by allocate().
66      */
67     void release(void* p);
68 
69     /**
70      * Returns true if there are no unreleased allocations.
71      */
isEmpty()72     bool isEmpty() const {
73         // If size is the same as preallocSize, there aren't any heap blocks, so currentBlock()
74         // is the inline head block.
75         return fAllocator.currentBlock() == fAllocator.headBlock() &&
76                fAllocator.currentBlock()->metadata() == 0;
77     }
78 
79     /**
80      * In debug mode, this reports the IDs of unfreed nodes via `SkDebugf`. This reporting is also
81      * performed automatically whenever a GrMemoryPool is destroyed.
82      * In release mode, this method is a no-op.
83      */
84     void reportLeaks() const;
85 
86     /**
87      * Returns the total allocated size of the GrMemoryPool minus any preallocated amount
88      */
size()89     size_t size() const { return fAllocator.totalSize() - fAllocator.preallocSize(); }
90 
91     /**
92      * Returns the preallocated size of the GrMemoryPool
93      */
preallocSize()94     size_t preallocSize() const {
95         // Account for the debug-only fields in this count, the offset is 0 for release builds
96         static_assert(std::is_standard_layout<GrMemoryPool>::value, "");
97         return offsetof(GrMemoryPool, fAllocator) + fAllocator.preallocSize();
98     }
99 
100     /**
101      * Frees any scratch blocks that are no longer being used.
102      */
resetScratchSpace()103     void resetScratchSpace() {
104         fAllocator.resetScratchSpace();
105     }
106 
107 #ifdef SK_DEBUG
108     void validate() const;
109 #endif
110 
111 private:
112     // Per-allocation overhead so that GrMemoryPool can always identify the block owning each and
113     // release all occupied bytes, including any resulting from alignment padding.
114     struct Header {
115         int fStart;
116         int fEnd;
117 #if defined(SK_DEBUG)
118         int fID;       // ID that can be used to track down leaks by clients.
119 #endif
120 #if defined(SK_DEBUG) || defined(SK_SANITIZE_ADDRESS)
121         uint32_t fSentinel; // set to a known value to check for memory stomping; poisoned in ASAN mode
122 #endif
123     };
124 
125     GrMemoryPool(size_t preallocSize, size_t minAllocSize);
126 
127 #ifdef SK_DEBUG
128     // Because this exists preallocSize wants to use offsetof, so keep GrMemoryPool standard layout
129     // without depending on SkTHashSet being standard layout. Note that std::unique_ptr may not be
130     // standard layout.
131     struct Debug{
132         SkTHashSet<int>  fAllocatedIDs;
133         int              fAllocationCount;
134     };
135     Debug* fDebug{nullptr};
136 #endif
137 
138     SkBlockAllocator fAllocator; // Must be the last field, in order to use extra allocated space
139 };
140 #endif
141