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