xref: /aosp_15_r20/external/angle/src/common/PoolAlloc.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // PoolAlloc.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //    Implements the class methods for PoolAllocator and Allocation classes.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "common/PoolAlloc.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include <assert.h>
13*8975f5c5SAndroid Build Coastguard Worker #include <stdint.h>
14*8975f5c5SAndroid Build Coastguard Worker #include <stdio.h>
15*8975f5c5SAndroid Build Coastguard Worker 
16*8975f5c5SAndroid Build Coastguard Worker #include "common/angleutils.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "common/mathutil.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "common/platform.h"
20*8975f5c5SAndroid Build Coastguard Worker #include "common/tls.h"
21*8975f5c5SAndroid Build Coastguard Worker 
22*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_WITH_ASAN)
23*8975f5c5SAndroid Build Coastguard Worker #    include <sanitizer/asan_interface.h>
24*8975f5c5SAndroid Build Coastguard Worker #endif
25*8975f5c5SAndroid Build Coastguard Worker 
26*8975f5c5SAndroid Build Coastguard Worker namespace angle
27*8975f5c5SAndroid Build Coastguard Worker {
28*8975f5c5SAndroid Build Coastguard Worker // If we are using guard blocks, we must track each individual allocation.  If we aren't using guard
29*8975f5c5SAndroid Build Coastguard Worker // blocks, these never get instantiated, so won't have any impact.
30*8975f5c5SAndroid Build Coastguard Worker 
31*8975f5c5SAndroid Build Coastguard Worker class Allocation
32*8975f5c5SAndroid Build Coastguard Worker {
33*8975f5c5SAndroid Build Coastguard Worker   public:
Allocation(size_t size,unsigned char * mem,Allocation * prev=0)34*8975f5c5SAndroid Build Coastguard Worker     Allocation(size_t size, unsigned char *mem, Allocation *prev = 0)
35*8975f5c5SAndroid Build Coastguard Worker         : mSize(size), mMem(mem), mPrevAlloc(prev)
36*8975f5c5SAndroid Build Coastguard Worker     {
37*8975f5c5SAndroid Build Coastguard Worker         // Allocations are bracketed:
38*8975f5c5SAndroid Build Coastguard Worker         //
39*8975f5c5SAndroid Build Coastguard Worker         //    [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
40*8975f5c5SAndroid Build Coastguard Worker         //
41*8975f5c5SAndroid Build Coastguard Worker         // This would be cleaner with if (kGuardBlockSize)..., but that makes the compiler print
42*8975f5c5SAndroid Build Coastguard Worker         // warnings about 0 length memsets, even with the if() protecting them.
43*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
44*8975f5c5SAndroid Build Coastguard Worker         memset(preGuard(), kGuardBlockBeginVal, kGuardBlockSize);
45*8975f5c5SAndroid Build Coastguard Worker         memset(data(), kUserDataFill, mSize);
46*8975f5c5SAndroid Build Coastguard Worker         memset(postGuard(), kGuardBlockEndVal, kGuardBlockSize);
47*8975f5c5SAndroid Build Coastguard Worker #endif
48*8975f5c5SAndroid Build Coastguard Worker     }
49*8975f5c5SAndroid Build Coastguard Worker 
50*8975f5c5SAndroid Build Coastguard Worker     void checkAllocList() const;
51*8975f5c5SAndroid Build Coastguard Worker 
AlignedHeaderSize(uint8_t * allocationBasePtr,size_t alignment)52*8975f5c5SAndroid Build Coastguard Worker     static size_t AlignedHeaderSize(uint8_t *allocationBasePtr, size_t alignment)
53*8975f5c5SAndroid Build Coastguard Worker     {
54*8975f5c5SAndroid Build Coastguard Worker         // Make sure that the data offset after the header is aligned to the given alignment.
55*8975f5c5SAndroid Build Coastguard Worker         size_t base = reinterpret_cast<size_t>(allocationBasePtr);
56*8975f5c5SAndroid Build Coastguard Worker         return rx::roundUpPow2(base + kGuardBlockSize + HeaderSize(), alignment) - base;
57*8975f5c5SAndroid Build Coastguard Worker     }
58*8975f5c5SAndroid Build Coastguard Worker 
59*8975f5c5SAndroid Build Coastguard Worker     // Return total size needed to accommodate user buffer of 'size',
60*8975f5c5SAndroid Build Coastguard Worker     // plus our tracking data and any necessary alignments.
AllocationSize(uint8_t * allocationBasePtr,size_t size,size_t alignment,size_t * preAllocationPaddingOut)61*8975f5c5SAndroid Build Coastguard Worker     static size_t AllocationSize(uint8_t *allocationBasePtr,
62*8975f5c5SAndroid Build Coastguard Worker                                  size_t size,
63*8975f5c5SAndroid Build Coastguard Worker                                  size_t alignment,
64*8975f5c5SAndroid Build Coastguard Worker                                  size_t *preAllocationPaddingOut)
65*8975f5c5SAndroid Build Coastguard Worker     {
66*8975f5c5SAndroid Build Coastguard Worker         // The allocation will be laid out as such:
67*8975f5c5SAndroid Build Coastguard Worker         //
68*8975f5c5SAndroid Build Coastguard Worker         //                      Aligned to |alignment|
69*8975f5c5SAndroid Build Coastguard Worker         //                               ^
70*8975f5c5SAndroid Build Coastguard Worker         //   preAllocationPaddingOut     |
71*8975f5c5SAndroid Build Coastguard Worker         //        ___^___                |
72*8975f5c5SAndroid Build Coastguard Worker         //       /       \               |
73*8975f5c5SAndroid Build Coastguard Worker         //       <padding>[header][guard][data][guard]
74*8975f5c5SAndroid Build Coastguard Worker         //       \___________ __________/
75*8975f5c5SAndroid Build Coastguard Worker         //                   V
76*8975f5c5SAndroid Build Coastguard Worker         //              dataOffset
77*8975f5c5SAndroid Build Coastguard Worker         //
78*8975f5c5SAndroid Build Coastguard Worker         // Note that alignment is at least as much as a pointer alignment, so the pointers in the
79*8975f5c5SAndroid Build Coastguard Worker         // header are also necessarily aligned appropriately.
80*8975f5c5SAndroid Build Coastguard Worker         //
81*8975f5c5SAndroid Build Coastguard Worker         size_t dataOffset        = AlignedHeaderSize(allocationBasePtr, alignment);
82*8975f5c5SAndroid Build Coastguard Worker         *preAllocationPaddingOut = dataOffset - HeaderSize() - kGuardBlockSize;
83*8975f5c5SAndroid Build Coastguard Worker 
84*8975f5c5SAndroid Build Coastguard Worker         return dataOffset + size + kGuardBlockSize;
85*8975f5c5SAndroid Build Coastguard Worker     }
86*8975f5c5SAndroid Build Coastguard Worker 
87*8975f5c5SAndroid Build Coastguard Worker     // Given memory pointing to |header|, returns |data|.
GetDataPointer(uint8_t * memory,size_t alignment)88*8975f5c5SAndroid Build Coastguard Worker     static uint8_t *GetDataPointer(uint8_t *memory, size_t alignment)
89*8975f5c5SAndroid Build Coastguard Worker     {
90*8975f5c5SAndroid Build Coastguard Worker         uint8_t *alignedPtr = memory + kGuardBlockSize + HeaderSize();
91*8975f5c5SAndroid Build Coastguard Worker 
92*8975f5c5SAndroid Build Coastguard Worker         // |memory| must be aligned already such that user data is aligned to |alignment|.
93*8975f5c5SAndroid Build Coastguard Worker         ASSERT((reinterpret_cast<uintptr_t>(alignedPtr) & (alignment - 1)) == 0);
94*8975f5c5SAndroid Build Coastguard Worker 
95*8975f5c5SAndroid Build Coastguard Worker         return alignedPtr;
96*8975f5c5SAndroid Build Coastguard Worker     }
97*8975f5c5SAndroid Build Coastguard Worker 
98*8975f5c5SAndroid Build Coastguard Worker   private:
99*8975f5c5SAndroid Build Coastguard Worker     void checkGuardBlock(unsigned char *blockMem, unsigned char val, const char *locText) const;
100*8975f5c5SAndroid Build Coastguard Worker 
checkAlloc() const101*8975f5c5SAndroid Build Coastguard Worker     void checkAlloc() const
102*8975f5c5SAndroid Build Coastguard Worker     {
103*8975f5c5SAndroid Build Coastguard Worker         checkGuardBlock(preGuard(), kGuardBlockBeginVal, "before");
104*8975f5c5SAndroid Build Coastguard Worker         checkGuardBlock(postGuard(), kGuardBlockEndVal, "after");
105*8975f5c5SAndroid Build Coastguard Worker     }
106*8975f5c5SAndroid Build Coastguard Worker 
107*8975f5c5SAndroid Build Coastguard Worker     // Find offsets to pre and post guard blocks, and user data buffer
preGuard() const108*8975f5c5SAndroid Build Coastguard Worker     unsigned char *preGuard() const { return mMem + HeaderSize(); }
data() const109*8975f5c5SAndroid Build Coastguard Worker     unsigned char *data() const { return preGuard() + kGuardBlockSize; }
postGuard() const110*8975f5c5SAndroid Build Coastguard Worker     unsigned char *postGuard() const { return data() + mSize; }
111*8975f5c5SAndroid Build Coastguard Worker     size_t mSize;            // size of the user data area
112*8975f5c5SAndroid Build Coastguard Worker     unsigned char *mMem;     // beginning of our allocation (points to header)
113*8975f5c5SAndroid Build Coastguard Worker     Allocation *mPrevAlloc;  // prior allocation in the chain
114*8975f5c5SAndroid Build Coastguard Worker 
115*8975f5c5SAndroid Build Coastguard Worker     static constexpr unsigned char kGuardBlockBeginVal = 0xfb;
116*8975f5c5SAndroid Build Coastguard Worker     static constexpr unsigned char kGuardBlockEndVal   = 0xfe;
117*8975f5c5SAndroid Build Coastguard Worker     static constexpr unsigned char kUserDataFill       = 0xcd;
118*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
119*8975f5c5SAndroid Build Coastguard Worker     static constexpr size_t kGuardBlockSize = 16;
HeaderSize()120*8975f5c5SAndroid Build Coastguard Worker     static constexpr size_t HeaderSize() { return sizeof(Allocation); }
121*8975f5c5SAndroid Build Coastguard Worker #else
122*8975f5c5SAndroid Build Coastguard Worker     static constexpr size_t kGuardBlockSize = 0;
HeaderSize()123*8975f5c5SAndroid Build Coastguard Worker     static constexpr size_t HeaderSize() { return 0; }
124*8975f5c5SAndroid Build Coastguard Worker #endif
125*8975f5c5SAndroid Build Coastguard Worker };
126*8975f5c5SAndroid Build Coastguard Worker 
127*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
128*8975f5c5SAndroid Build Coastguard Worker class PageHeader
129*8975f5c5SAndroid Build Coastguard Worker {
130*8975f5c5SAndroid Build Coastguard Worker   public:
PageHeader(PageHeader * nextPage,size_t pageCount)131*8975f5c5SAndroid Build Coastguard Worker     PageHeader(PageHeader *nextPage, size_t pageCount)
132*8975f5c5SAndroid Build Coastguard Worker         : nextPage(nextPage),
133*8975f5c5SAndroid Build Coastguard Worker           pageCount(pageCount)
134*8975f5c5SAndroid Build Coastguard Worker #    if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
135*8975f5c5SAndroid Build Coastguard Worker           ,
136*8975f5c5SAndroid Build Coastguard Worker           lastAllocation(nullptr)
137*8975f5c5SAndroid Build Coastguard Worker #    endif
138*8975f5c5SAndroid Build Coastguard Worker     {}
139*8975f5c5SAndroid Build Coastguard Worker 
~PageHeader()140*8975f5c5SAndroid Build Coastguard Worker     ~PageHeader()
141*8975f5c5SAndroid Build Coastguard Worker     {
142*8975f5c5SAndroid Build Coastguard Worker #    if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
143*8975f5c5SAndroid Build Coastguard Worker         if (lastAllocation)
144*8975f5c5SAndroid Build Coastguard Worker         {
145*8975f5c5SAndroid Build Coastguard Worker             lastAllocation->checkAllocList();
146*8975f5c5SAndroid Build Coastguard Worker         }
147*8975f5c5SAndroid Build Coastguard Worker #    endif
148*8975f5c5SAndroid Build Coastguard Worker     }
149*8975f5c5SAndroid Build Coastguard Worker 
150*8975f5c5SAndroid Build Coastguard Worker     PageHeader *nextPage;
151*8975f5c5SAndroid Build Coastguard Worker     size_t pageCount;
152*8975f5c5SAndroid Build Coastguard Worker #    if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
153*8975f5c5SAndroid Build Coastguard Worker     Allocation *lastAllocation;
154*8975f5c5SAndroid Build Coastguard Worker #    endif
155*8975f5c5SAndroid Build Coastguard Worker };
156*8975f5c5SAndroid Build Coastguard Worker #endif
157*8975f5c5SAndroid Build Coastguard Worker 
158*8975f5c5SAndroid Build Coastguard Worker //
159*8975f5c5SAndroid Build Coastguard Worker // Implement the functionality of the PoolAllocator class, which
160*8975f5c5SAndroid Build Coastguard Worker // is documented in PoolAlloc.h.
161*8975f5c5SAndroid Build Coastguard Worker //
PoolAllocator(int growthIncrement,int allocationAlignment)162*8975f5c5SAndroid Build Coastguard Worker PoolAllocator::PoolAllocator(int growthIncrement, int allocationAlignment)
163*8975f5c5SAndroid Build Coastguard Worker     : mAlignment(allocationAlignment),
164*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
165*8975f5c5SAndroid Build Coastguard Worker       mPageSize(growthIncrement),
166*8975f5c5SAndroid Build Coastguard Worker       mFreeList(nullptr),
167*8975f5c5SAndroid Build Coastguard Worker       mInUseList(nullptr),
168*8975f5c5SAndroid Build Coastguard Worker       mNumCalls(0),
169*8975f5c5SAndroid Build Coastguard Worker       mTotalBytes(0),
170*8975f5c5SAndroid Build Coastguard Worker #endif
171*8975f5c5SAndroid Build Coastguard Worker       mLocked(false)
172*8975f5c5SAndroid Build Coastguard Worker {
173*8975f5c5SAndroid Build Coastguard Worker     initialize(growthIncrement, allocationAlignment);
174*8975f5c5SAndroid Build Coastguard Worker }
175*8975f5c5SAndroid Build Coastguard Worker 
initialize(int pageSize,int alignment)176*8975f5c5SAndroid Build Coastguard Worker void PoolAllocator::initialize(int pageSize, int alignment)
177*8975f5c5SAndroid Build Coastguard Worker {
178*8975f5c5SAndroid Build Coastguard Worker     mAlignment = alignment;
179*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
180*8975f5c5SAndroid Build Coastguard Worker     mPageSize       = pageSize;
181*8975f5c5SAndroid Build Coastguard Worker     mPageHeaderSkip = sizeof(PageHeader);
182*8975f5c5SAndroid Build Coastguard Worker 
183*8975f5c5SAndroid Build Coastguard Worker     // Alignment == 1 is a special fast-path where fastAllocate() is enabled
184*8975f5c5SAndroid Build Coastguard Worker     if (mAlignment != 1)
185*8975f5c5SAndroid Build Coastguard Worker     {
186*8975f5c5SAndroid Build Coastguard Worker #endif
187*8975f5c5SAndroid Build Coastguard Worker         // Adjust mAlignment to be at least pointer aligned and
188*8975f5c5SAndroid Build Coastguard Worker         // power of 2.
189*8975f5c5SAndroid Build Coastguard Worker         //
190*8975f5c5SAndroid Build Coastguard Worker         size_t minAlign = sizeof(void *);
191*8975f5c5SAndroid Build Coastguard Worker         if (mAlignment < minAlign)
192*8975f5c5SAndroid Build Coastguard Worker         {
193*8975f5c5SAndroid Build Coastguard Worker             mAlignment = minAlign;
194*8975f5c5SAndroid Build Coastguard Worker         }
195*8975f5c5SAndroid Build Coastguard Worker         mAlignment = gl::ceilPow2(static_cast<unsigned int>(mAlignment));
196*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
197*8975f5c5SAndroid Build Coastguard Worker     }
198*8975f5c5SAndroid Build Coastguard Worker     //
199*8975f5c5SAndroid Build Coastguard Worker     // Don't allow page sizes we know are smaller than all common
200*8975f5c5SAndroid Build Coastguard Worker     // OS page sizes.
201*8975f5c5SAndroid Build Coastguard Worker     //
202*8975f5c5SAndroid Build Coastguard Worker     if (mPageSize < 4 * 1024)
203*8975f5c5SAndroid Build Coastguard Worker     {
204*8975f5c5SAndroid Build Coastguard Worker         mPageSize = 4 * 1024;
205*8975f5c5SAndroid Build Coastguard Worker     }
206*8975f5c5SAndroid Build Coastguard Worker 
207*8975f5c5SAndroid Build Coastguard Worker     //
208*8975f5c5SAndroid Build Coastguard Worker     // A large mCurrentPageOffset indicates a new page needs to
209*8975f5c5SAndroid Build Coastguard Worker     // be obtained to allocate memory.
210*8975f5c5SAndroid Build Coastguard Worker     //
211*8975f5c5SAndroid Build Coastguard Worker     mCurrentPageOffset = mPageSize;
212*8975f5c5SAndroid Build Coastguard Worker 
213*8975f5c5SAndroid Build Coastguard Worker #else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
214*8975f5c5SAndroid Build Coastguard Worker     mStack.push_back({});
215*8975f5c5SAndroid Build Coastguard Worker #endif
216*8975f5c5SAndroid Build Coastguard Worker }
217*8975f5c5SAndroid Build Coastguard Worker 
~PoolAllocator()218*8975f5c5SAndroid Build Coastguard Worker PoolAllocator::~PoolAllocator()
219*8975f5c5SAndroid Build Coastguard Worker {
220*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
221*8975f5c5SAndroid Build Coastguard Worker     while (mInUseList)
222*8975f5c5SAndroid Build Coastguard Worker     {
223*8975f5c5SAndroid Build Coastguard Worker         PageHeader *next = mInUseList->nextPage;
224*8975f5c5SAndroid Build Coastguard Worker         mInUseList->~PageHeader();
225*8975f5c5SAndroid Build Coastguard Worker         delete[] reinterpret_cast<char *>(mInUseList);
226*8975f5c5SAndroid Build Coastguard Worker         mInUseList = next;
227*8975f5c5SAndroid Build Coastguard Worker     }
228*8975f5c5SAndroid Build Coastguard Worker     // We should not check the guard blocks
229*8975f5c5SAndroid Build Coastguard Worker     // here, because we did it already when the block was
230*8975f5c5SAndroid Build Coastguard Worker     // placed into the free list.
231*8975f5c5SAndroid Build Coastguard Worker     //
232*8975f5c5SAndroid Build Coastguard Worker     while (mFreeList)
233*8975f5c5SAndroid Build Coastguard Worker     {
234*8975f5c5SAndroid Build Coastguard Worker         PageHeader *next = mFreeList->nextPage;
235*8975f5c5SAndroid Build Coastguard Worker         delete[] reinterpret_cast<char *>(mFreeList);
236*8975f5c5SAndroid Build Coastguard Worker         mFreeList = next;
237*8975f5c5SAndroid Build Coastguard Worker     }
238*8975f5c5SAndroid Build Coastguard Worker #else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
239*8975f5c5SAndroid Build Coastguard Worker     for (auto &allocs : mStack)
240*8975f5c5SAndroid Build Coastguard Worker     {
241*8975f5c5SAndroid Build Coastguard Worker         for (auto alloc : allocs)
242*8975f5c5SAndroid Build Coastguard Worker         {
243*8975f5c5SAndroid Build Coastguard Worker             free(alloc);
244*8975f5c5SAndroid Build Coastguard Worker         }
245*8975f5c5SAndroid Build Coastguard Worker     }
246*8975f5c5SAndroid Build Coastguard Worker     mStack.clear();
247*8975f5c5SAndroid Build Coastguard Worker #endif
248*8975f5c5SAndroid Build Coastguard Worker }
249*8975f5c5SAndroid Build Coastguard Worker 
250*8975f5c5SAndroid Build Coastguard Worker //
251*8975f5c5SAndroid Build Coastguard Worker // Check a single guard block for damage
252*8975f5c5SAndroid Build Coastguard Worker //
checkGuardBlock(unsigned char * blockMem,unsigned char val,const char * locText) const253*8975f5c5SAndroid Build Coastguard Worker void Allocation::checkGuardBlock(unsigned char *blockMem,
254*8975f5c5SAndroid Build Coastguard Worker                                  unsigned char val,
255*8975f5c5SAndroid Build Coastguard Worker                                  const char *locText) const
256*8975f5c5SAndroid Build Coastguard Worker {
257*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
258*8975f5c5SAndroid Build Coastguard Worker     for (size_t x = 0; x < kGuardBlockSize; x++)
259*8975f5c5SAndroid Build Coastguard Worker     {
260*8975f5c5SAndroid Build Coastguard Worker         if (blockMem[x] != val)
261*8975f5c5SAndroid Build Coastguard Worker         {
262*8975f5c5SAndroid Build Coastguard Worker             char assertMsg[80];
263*8975f5c5SAndroid Build Coastguard Worker             // We don't print the assert message.  It's here just to be helpful.
264*8975f5c5SAndroid Build Coastguard Worker             snprintf(assertMsg, sizeof(assertMsg),
265*8975f5c5SAndroid Build Coastguard Worker                      "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", locText, mSize, data());
266*8975f5c5SAndroid Build Coastguard Worker             assert(0 && "PoolAlloc: Damage in guard block");
267*8975f5c5SAndroid Build Coastguard Worker         }
268*8975f5c5SAndroid Build Coastguard Worker     }
269*8975f5c5SAndroid Build Coastguard Worker #endif
270*8975f5c5SAndroid Build Coastguard Worker }
271*8975f5c5SAndroid Build Coastguard Worker 
push()272*8975f5c5SAndroid Build Coastguard Worker void PoolAllocator::push()
273*8975f5c5SAndroid Build Coastguard Worker {
274*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
275*8975f5c5SAndroid Build Coastguard Worker     AllocState state = {mCurrentPageOffset, mInUseList};
276*8975f5c5SAndroid Build Coastguard Worker 
277*8975f5c5SAndroid Build Coastguard Worker     mStack.push_back(state);
278*8975f5c5SAndroid Build Coastguard Worker 
279*8975f5c5SAndroid Build Coastguard Worker     //
280*8975f5c5SAndroid Build Coastguard Worker     // Indicate there is no current page to allocate from.
281*8975f5c5SAndroid Build Coastguard Worker     //
282*8975f5c5SAndroid Build Coastguard Worker     mCurrentPageOffset = mPageSize;
283*8975f5c5SAndroid Build Coastguard Worker #else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
284*8975f5c5SAndroid Build Coastguard Worker     mStack.push_back({});
285*8975f5c5SAndroid Build Coastguard Worker #endif
286*8975f5c5SAndroid Build Coastguard Worker }
287*8975f5c5SAndroid Build Coastguard Worker 
288*8975f5c5SAndroid Build Coastguard Worker // Do a mass-deallocation of all the individual allocations that have occurred since the last
289*8975f5c5SAndroid Build Coastguard Worker // push(), or since the last pop(), or since the object's creation.
290*8975f5c5SAndroid Build Coastguard Worker //
291*8975f5c5SAndroid Build Coastguard Worker // Single-page allocations are saved for future use unless the release strategy is All.
pop(ReleaseStrategy releaseStrategy)292*8975f5c5SAndroid Build Coastguard Worker void PoolAllocator::pop(ReleaseStrategy releaseStrategy)
293*8975f5c5SAndroid Build Coastguard Worker {
294*8975f5c5SAndroid Build Coastguard Worker     if (mStack.size() < 1)
295*8975f5c5SAndroid Build Coastguard Worker     {
296*8975f5c5SAndroid Build Coastguard Worker         return;
297*8975f5c5SAndroid Build Coastguard Worker     }
298*8975f5c5SAndroid Build Coastguard Worker 
299*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
300*8975f5c5SAndroid Build Coastguard Worker     PageHeader *page   = mStack.back().page;
301*8975f5c5SAndroid Build Coastguard Worker     mCurrentPageOffset = mStack.back().offset;
302*8975f5c5SAndroid Build Coastguard Worker 
303*8975f5c5SAndroid Build Coastguard Worker     while (mInUseList != page)
304*8975f5c5SAndroid Build Coastguard Worker     {
305*8975f5c5SAndroid Build Coastguard Worker         // Grab the pageCount before calling the destructor.  While the destructor doesn't actually
306*8975f5c5SAndroid Build Coastguard Worker         // touch this variable, it's confusing MSAN.
307*8975f5c5SAndroid Build Coastguard Worker         const size_t pageCount = mInUseList->pageCount;
308*8975f5c5SAndroid Build Coastguard Worker         PageHeader *nextInUse  = mInUseList->nextPage;
309*8975f5c5SAndroid Build Coastguard Worker 
310*8975f5c5SAndroid Build Coastguard Worker         // invoke destructor to free allocation list
311*8975f5c5SAndroid Build Coastguard Worker         mInUseList->~PageHeader();
312*8975f5c5SAndroid Build Coastguard Worker 
313*8975f5c5SAndroid Build Coastguard Worker         if (pageCount > 1 || releaseStrategy == ReleaseStrategy::All)
314*8975f5c5SAndroid Build Coastguard Worker         {
315*8975f5c5SAndroid Build Coastguard Worker             delete[] reinterpret_cast<char *>(mInUseList);
316*8975f5c5SAndroid Build Coastguard Worker         }
317*8975f5c5SAndroid Build Coastguard Worker         else
318*8975f5c5SAndroid Build Coastguard Worker         {
319*8975f5c5SAndroid Build Coastguard Worker #    if defined(ANGLE_WITH_ASAN)
320*8975f5c5SAndroid Build Coastguard Worker             // Clear any container annotations left over from when the memory
321*8975f5c5SAndroid Build Coastguard Worker             // was last used. (crbug.com/1419798)
322*8975f5c5SAndroid Build Coastguard Worker             __asan_unpoison_memory_region(mInUseList, mPageSize);
323*8975f5c5SAndroid Build Coastguard Worker #    endif
324*8975f5c5SAndroid Build Coastguard Worker             mInUseList->nextPage = mFreeList;
325*8975f5c5SAndroid Build Coastguard Worker             mFreeList            = mInUseList;
326*8975f5c5SAndroid Build Coastguard Worker         }
327*8975f5c5SAndroid Build Coastguard Worker         mInUseList = nextInUse;
328*8975f5c5SAndroid Build Coastguard Worker     }
329*8975f5c5SAndroid Build Coastguard Worker 
330*8975f5c5SAndroid Build Coastguard Worker     mStack.pop_back();
331*8975f5c5SAndroid Build Coastguard Worker #else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
332*8975f5c5SAndroid Build Coastguard Worker     for (auto &alloc : mStack.back())
333*8975f5c5SAndroid Build Coastguard Worker     {
334*8975f5c5SAndroid Build Coastguard Worker         free(alloc);
335*8975f5c5SAndroid Build Coastguard Worker     }
336*8975f5c5SAndroid Build Coastguard Worker     mStack.pop_back();
337*8975f5c5SAndroid Build Coastguard Worker #endif
338*8975f5c5SAndroid Build Coastguard Worker }
339*8975f5c5SAndroid Build Coastguard Worker 
340*8975f5c5SAndroid Build Coastguard Worker //
341*8975f5c5SAndroid Build Coastguard Worker // Do a mass-deallocation of all the individual allocations
342*8975f5c5SAndroid Build Coastguard Worker // that have occurred.
343*8975f5c5SAndroid Build Coastguard Worker //
popAll()344*8975f5c5SAndroid Build Coastguard Worker void PoolAllocator::popAll()
345*8975f5c5SAndroid Build Coastguard Worker {
346*8975f5c5SAndroid Build Coastguard Worker     while (mStack.size() > 0)
347*8975f5c5SAndroid Build Coastguard Worker         pop();
348*8975f5c5SAndroid Build Coastguard Worker }
349*8975f5c5SAndroid Build Coastguard Worker 
allocate(size_t numBytes)350*8975f5c5SAndroid Build Coastguard Worker void *PoolAllocator::allocate(size_t numBytes)
351*8975f5c5SAndroid Build Coastguard Worker {
352*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mLocked);
353*8975f5c5SAndroid Build Coastguard Worker 
354*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
355*8975f5c5SAndroid Build Coastguard Worker     //
356*8975f5c5SAndroid Build Coastguard Worker     // Just keep some interesting statistics.
357*8975f5c5SAndroid Build Coastguard Worker     //
358*8975f5c5SAndroid Build Coastguard Worker     ++mNumCalls;
359*8975f5c5SAndroid Build Coastguard Worker     mTotalBytes += numBytes;
360*8975f5c5SAndroid Build Coastguard Worker 
361*8975f5c5SAndroid Build Coastguard Worker     uint8_t *currentPagePtr = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset;
362*8975f5c5SAndroid Build Coastguard Worker 
363*8975f5c5SAndroid Build Coastguard Worker     size_t preAllocationPadding = 0;
364*8975f5c5SAndroid Build Coastguard Worker     size_t allocationSize =
365*8975f5c5SAndroid Build Coastguard Worker         Allocation::AllocationSize(currentPagePtr, numBytes, mAlignment, &preAllocationPadding);
366*8975f5c5SAndroid Build Coastguard Worker 
367*8975f5c5SAndroid Build Coastguard Worker     // Integer overflow is unexpected.
368*8975f5c5SAndroid Build Coastguard Worker     ASSERT(allocationSize >= numBytes);
369*8975f5c5SAndroid Build Coastguard Worker 
370*8975f5c5SAndroid Build Coastguard Worker     // Do the allocation, most likely case first, for efficiency.
371*8975f5c5SAndroid Build Coastguard Worker     if (allocationSize <= mPageSize - mCurrentPageOffset)
372*8975f5c5SAndroid Build Coastguard Worker     {
373*8975f5c5SAndroid Build Coastguard Worker         // There is enough room to allocate from the current page at mCurrentPageOffset.
374*8975f5c5SAndroid Build Coastguard Worker         uint8_t *memory = currentPagePtr + preAllocationPadding;
375*8975f5c5SAndroid Build Coastguard Worker         mCurrentPageOffset += allocationSize;
376*8975f5c5SAndroid Build Coastguard Worker 
377*8975f5c5SAndroid Build Coastguard Worker         return initializeAllocation(memory, numBytes);
378*8975f5c5SAndroid Build Coastguard Worker     }
379*8975f5c5SAndroid Build Coastguard Worker 
380*8975f5c5SAndroid Build Coastguard Worker     if (allocationSize > mPageSize - mPageHeaderSkip)
381*8975f5c5SAndroid Build Coastguard Worker     {
382*8975f5c5SAndroid Build Coastguard Worker         // If the allocation is larger than a whole page, do a multi-page allocation.  These are not
383*8975f5c5SAndroid Build Coastguard Worker         // mixed with the others.  The OS is efficient in allocating and freeing multiple pages.
384*8975f5c5SAndroid Build Coastguard Worker 
385*8975f5c5SAndroid Build Coastguard Worker         // We don't know what the alignment of the new allocated memory will be, so conservatively
386*8975f5c5SAndroid Build Coastguard Worker         // allocate enough memory for up to alignment extra bytes being needed.
387*8975f5c5SAndroid Build Coastguard Worker         allocationSize = Allocation::AllocationSize(reinterpret_cast<uint8_t *>(mPageHeaderSkip),
388*8975f5c5SAndroid Build Coastguard Worker                                                     numBytes, mAlignment, &preAllocationPadding);
389*8975f5c5SAndroid Build Coastguard Worker 
390*8975f5c5SAndroid Build Coastguard Worker         size_t numBytesToAlloc = allocationSize + mPageHeaderSkip + mAlignment;
391*8975f5c5SAndroid Build Coastguard Worker 
392*8975f5c5SAndroid Build Coastguard Worker         // Integer overflow is unexpected.
393*8975f5c5SAndroid Build Coastguard Worker         ASSERT(numBytesToAlloc >= allocationSize);
394*8975f5c5SAndroid Build Coastguard Worker 
395*8975f5c5SAndroid Build Coastguard Worker         PageHeader *memory = reinterpret_cast<PageHeader *>(::new char[numBytesToAlloc]);
396*8975f5c5SAndroid Build Coastguard Worker         if (memory == nullptr)
397*8975f5c5SAndroid Build Coastguard Worker         {
398*8975f5c5SAndroid Build Coastguard Worker             return nullptr;
399*8975f5c5SAndroid Build Coastguard Worker         }
400*8975f5c5SAndroid Build Coastguard Worker 
401*8975f5c5SAndroid Build Coastguard Worker         // Use placement-new to initialize header
402*8975f5c5SAndroid Build Coastguard Worker         new (memory) PageHeader(mInUseList, (numBytesToAlloc + mPageSize - 1) / mPageSize);
403*8975f5c5SAndroid Build Coastguard Worker         mInUseList = memory;
404*8975f5c5SAndroid Build Coastguard Worker 
405*8975f5c5SAndroid Build Coastguard Worker         // Make next allocation come from a new page
406*8975f5c5SAndroid Build Coastguard Worker         mCurrentPageOffset = mPageSize;
407*8975f5c5SAndroid Build Coastguard Worker 
408*8975f5c5SAndroid Build Coastguard Worker         // Now that we actually have the pointer, make sure the data pointer will be aligned.
409*8975f5c5SAndroid Build Coastguard Worker         currentPagePtr = reinterpret_cast<uint8_t *>(memory) + mPageHeaderSkip;
410*8975f5c5SAndroid Build Coastguard Worker         Allocation::AllocationSize(currentPagePtr, numBytes, mAlignment, &preAllocationPadding);
411*8975f5c5SAndroid Build Coastguard Worker 
412*8975f5c5SAndroid Build Coastguard Worker         return initializeAllocation(currentPagePtr + preAllocationPadding, numBytes);
413*8975f5c5SAndroid Build Coastguard Worker     }
414*8975f5c5SAndroid Build Coastguard Worker 
415*8975f5c5SAndroid Build Coastguard Worker     uint8_t *newPageAddr = allocateNewPage(numBytes);
416*8975f5c5SAndroid Build Coastguard Worker     return initializeAllocation(newPageAddr, numBytes);
417*8975f5c5SAndroid Build Coastguard Worker 
418*8975f5c5SAndroid Build Coastguard Worker #else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
419*8975f5c5SAndroid Build Coastguard Worker 
420*8975f5c5SAndroid Build Coastguard Worker     void *alloc = malloc(numBytes + mAlignment - 1);
421*8975f5c5SAndroid Build Coastguard Worker     mStack.back().push_back(alloc);
422*8975f5c5SAndroid Build Coastguard Worker 
423*8975f5c5SAndroid Build Coastguard Worker     intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
424*8975f5c5SAndroid Build Coastguard Worker     intAlloc          = rx::roundUpPow2<intptr_t>(intAlloc, mAlignment);
425*8975f5c5SAndroid Build Coastguard Worker     return reinterpret_cast<void *>(intAlloc);
426*8975f5c5SAndroid Build Coastguard Worker #endif
427*8975f5c5SAndroid Build Coastguard Worker }
428*8975f5c5SAndroid Build Coastguard Worker 
429*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_DISABLE_POOL_ALLOC)
allocateNewPage(size_t numBytes)430*8975f5c5SAndroid Build Coastguard Worker uint8_t *PoolAllocator::allocateNewPage(size_t numBytes)
431*8975f5c5SAndroid Build Coastguard Worker {
432*8975f5c5SAndroid Build Coastguard Worker     // Need a simple page to allocate from.  Pick a page from the free list, if any.  Otherwise need
433*8975f5c5SAndroid Build Coastguard Worker     // to make the allocation.
434*8975f5c5SAndroid Build Coastguard Worker     PageHeader *memory;
435*8975f5c5SAndroid Build Coastguard Worker     if (mFreeList)
436*8975f5c5SAndroid Build Coastguard Worker     {
437*8975f5c5SAndroid Build Coastguard Worker         memory    = mFreeList;
438*8975f5c5SAndroid Build Coastguard Worker         mFreeList = mFreeList->nextPage;
439*8975f5c5SAndroid Build Coastguard Worker     }
440*8975f5c5SAndroid Build Coastguard Worker     else
441*8975f5c5SAndroid Build Coastguard Worker     {
442*8975f5c5SAndroid Build Coastguard Worker         memory = reinterpret_cast<PageHeader *>(::new char[mPageSize]);
443*8975f5c5SAndroid Build Coastguard Worker         if (memory == nullptr)
444*8975f5c5SAndroid Build Coastguard Worker         {
445*8975f5c5SAndroid Build Coastguard Worker             return nullptr;
446*8975f5c5SAndroid Build Coastguard Worker         }
447*8975f5c5SAndroid Build Coastguard Worker     }
448*8975f5c5SAndroid Build Coastguard Worker     // Use placement-new to initialize header
449*8975f5c5SAndroid Build Coastguard Worker     new (memory) PageHeader(mInUseList, 1);
450*8975f5c5SAndroid Build Coastguard Worker     mInUseList = memory;
451*8975f5c5SAndroid Build Coastguard Worker 
452*8975f5c5SAndroid Build Coastguard Worker     // Leave room for the page header.
453*8975f5c5SAndroid Build Coastguard Worker     mCurrentPageOffset      = mPageHeaderSkip;
454*8975f5c5SAndroid Build Coastguard Worker     uint8_t *currentPagePtr = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset;
455*8975f5c5SAndroid Build Coastguard Worker 
456*8975f5c5SAndroid Build Coastguard Worker     size_t preAllocationPadding = 0;
457*8975f5c5SAndroid Build Coastguard Worker     size_t allocationSize =
458*8975f5c5SAndroid Build Coastguard Worker         Allocation::AllocationSize(currentPagePtr, numBytes, mAlignment, &preAllocationPadding);
459*8975f5c5SAndroid Build Coastguard Worker 
460*8975f5c5SAndroid Build Coastguard Worker     mCurrentPageOffset += allocationSize;
461*8975f5c5SAndroid Build Coastguard Worker 
462*8975f5c5SAndroid Build Coastguard Worker     // The new allocation is made after the page header and any alignment required before it.
463*8975f5c5SAndroid Build Coastguard Worker     return reinterpret_cast<uint8_t *>(mInUseList) + mPageHeaderSkip + preAllocationPadding;
464*8975f5c5SAndroid Build Coastguard Worker }
465*8975f5c5SAndroid Build Coastguard Worker 
initializeAllocation(uint8_t * memory,size_t numBytes)466*8975f5c5SAndroid Build Coastguard Worker void *PoolAllocator::initializeAllocation(uint8_t *memory, size_t numBytes)
467*8975f5c5SAndroid Build Coastguard Worker {
468*8975f5c5SAndroid Build Coastguard Worker #    if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
469*8975f5c5SAndroid Build Coastguard Worker     new (memory) Allocation(numBytes, memory, mInUseList->lastAllocation);
470*8975f5c5SAndroid Build Coastguard Worker     mInUseList->lastAllocation = reinterpret_cast<Allocation *>(memory);
471*8975f5c5SAndroid Build Coastguard Worker #    endif
472*8975f5c5SAndroid Build Coastguard Worker 
473*8975f5c5SAndroid Build Coastguard Worker     return Allocation::GetDataPointer(memory, mAlignment);
474*8975f5c5SAndroid Build Coastguard Worker }
475*8975f5c5SAndroid Build Coastguard Worker #endif
476*8975f5c5SAndroid Build Coastguard Worker 
lock()477*8975f5c5SAndroid Build Coastguard Worker void PoolAllocator::lock()
478*8975f5c5SAndroid Build Coastguard Worker {
479*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mLocked);
480*8975f5c5SAndroid Build Coastguard Worker     mLocked = true;
481*8975f5c5SAndroid Build Coastguard Worker }
482*8975f5c5SAndroid Build Coastguard Worker 
unlock()483*8975f5c5SAndroid Build Coastguard Worker void PoolAllocator::unlock()
484*8975f5c5SAndroid Build Coastguard Worker {
485*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLocked);
486*8975f5c5SAndroid Build Coastguard Worker     mLocked = false;
487*8975f5c5SAndroid Build Coastguard Worker }
488*8975f5c5SAndroid Build Coastguard Worker 
489*8975f5c5SAndroid Build Coastguard Worker //
490*8975f5c5SAndroid Build Coastguard Worker // Check all allocations in a list for damage by calling check on each.
491*8975f5c5SAndroid Build Coastguard Worker //
checkAllocList() const492*8975f5c5SAndroid Build Coastguard Worker void Allocation::checkAllocList() const
493*8975f5c5SAndroid Build Coastguard Worker {
494*8975f5c5SAndroid Build Coastguard Worker     for (const Allocation *alloc = this; alloc != nullptr; alloc = alloc->mPrevAlloc)
495*8975f5c5SAndroid Build Coastguard Worker     {
496*8975f5c5SAndroid Build Coastguard Worker         alloc->checkAlloc();
497*8975f5c5SAndroid Build Coastguard Worker     }
498*8975f5c5SAndroid Build Coastguard Worker }
499*8975f5c5SAndroid Build Coastguard Worker 
500*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
501