Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/common/PoolAlloc.cpp
1693 views
1
//
2
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
5
//
6
// PoolAlloc.cpp:
7
// Implements the class methods for PoolAllocator and Allocation classes.
8
//
9
10
#include "common/PoolAlloc.h"
11
12
#include <assert.h>
13
#include <stdint.h>
14
#include <stdio.h>
15
16
#include "common/angleutils.h"
17
#include "common/debug.h"
18
#include "common/mathutil.h"
19
#include "common/platform.h"
20
#include "common/tls.h"
21
22
namespace angle
23
{
24
25
//
26
// Implement the functionality of the PoolAllocator class, which
27
// is documented in PoolAlloc.h.
28
//
29
PoolAllocator::PoolAllocator(int growthIncrement, int allocationAlignment)
30
: mAlignment(allocationAlignment),
31
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
32
mPageSize(growthIncrement),
33
mFreeList(0),
34
mInUseList(0),
35
mNumCalls(0),
36
mTotalBytes(0),
37
#endif
38
mLocked(false)
39
{
40
initialize(growthIncrement, allocationAlignment);
41
}
42
43
void PoolAllocator::initialize(int pageSize, int alignment)
44
{
45
mAlignment = alignment;
46
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
47
mPageSize = pageSize;
48
if (mAlignment == 1)
49
{
50
// This is a special fast-path where fastAllocation() is enabled
51
mAlignmentMask = 0;
52
mHeaderSkip = sizeof(Header);
53
}
54
else
55
{
56
#endif
57
//
58
// Adjust mAlignment to be at least pointer aligned and
59
// power of 2.
60
//
61
size_t minAlign = sizeof(void *);
62
mAlignment &= ~(minAlign - 1);
63
if (mAlignment < minAlign)
64
mAlignment = minAlign;
65
mAlignment = gl::ceilPow2(static_cast<unsigned int>(mAlignment));
66
mAlignmentMask = mAlignment - 1;
67
68
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
69
//
70
// Align header skip
71
//
72
mHeaderSkip = minAlign;
73
if (mHeaderSkip < sizeof(Header))
74
{
75
mHeaderSkip = rx::roundUpPow2(sizeof(Header), mAlignment);
76
}
77
}
78
//
79
// Don't allow page sizes we know are smaller than all common
80
// OS page sizes.
81
//
82
if (mPageSize < 4 * 1024)
83
mPageSize = 4 * 1024;
84
//
85
// A large mCurrentPageOffset indicates a new page needs to
86
// be obtained to allocate memory.
87
//
88
mCurrentPageOffset = mPageSize;
89
#else // !defined(ANGLE_DISABLE_POOL_ALLOC)
90
mStack.push_back({});
91
#endif
92
}
93
94
PoolAllocator::~PoolAllocator()
95
{
96
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
97
while (mInUseList)
98
{
99
Header *next = mInUseList->nextPage;
100
mInUseList->~Header();
101
delete[] reinterpret_cast<char *>(mInUseList);
102
mInUseList = next;
103
}
104
// We should not check the guard blocks
105
// here, because we did it already when the block was
106
// placed into the free list.
107
//
108
while (mFreeList)
109
{
110
Header *next = mFreeList->nextPage;
111
delete[] reinterpret_cast<char *>(mFreeList);
112
mFreeList = next;
113
}
114
#else // !defined(ANGLE_DISABLE_POOL_ALLOC)
115
for (auto &allocs : mStack)
116
{
117
for (auto alloc : allocs)
118
{
119
free(alloc);
120
}
121
}
122
mStack.clear();
123
#endif
124
}
125
126
//
127
// Check a single guard block for damage
128
//
129
void Allocation::checkGuardBlock(unsigned char *blockMem,
130
unsigned char val,
131
const char *locText) const
132
{
133
#if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
134
for (size_t x = 0; x < kGuardBlockSize; x++)
135
{
136
if (blockMem[x] != val)
137
{
138
char assertMsg[80];
139
// We don't print the assert message. It's here just to be helpful.
140
snprintf(assertMsg, sizeof(assertMsg),
141
"PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", locText, mSize, data());
142
assert(0 && "PoolAlloc: Damage in guard block");
143
}
144
}
145
#endif
146
}
147
148
void PoolAllocator::push()
149
{
150
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
151
AllocState state = {mCurrentPageOffset, mInUseList};
152
153
mStack.push_back(state);
154
155
//
156
// Indicate there is no current page to allocate from.
157
//
158
mCurrentPageOffset = mPageSize;
159
#else // !defined(ANGLE_DISABLE_POOL_ALLOC)
160
mStack.push_back({});
161
#endif
162
}
163
164
//
165
// Do a mass-deallocation of all the individual allocations
166
// that have occurred since the last push(), or since the
167
// last pop(), or since the object's creation.
168
//
169
// The deallocated pages are saved for future allocations.
170
//
171
void PoolAllocator::pop()
172
{
173
if (mStack.size() < 1)
174
return;
175
176
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
177
Header *page = mStack.back().page;
178
mCurrentPageOffset = mStack.back().offset;
179
180
while (mInUseList != page)
181
{
182
// invoke destructor to free allocation list
183
mInUseList->~Header();
184
185
Header *nextInUse = mInUseList->nextPage;
186
if (mInUseList->pageCount > 1)
187
delete[] reinterpret_cast<char *>(mInUseList);
188
else
189
{
190
mInUseList->nextPage = mFreeList;
191
mFreeList = mInUseList;
192
}
193
mInUseList = nextInUse;
194
}
195
196
mStack.pop_back();
197
#else // !defined(ANGLE_DISABLE_POOL_ALLOC)
198
for (auto &alloc : mStack.back())
199
{
200
free(alloc);
201
}
202
mStack.pop_back();
203
#endif
204
}
205
206
//
207
// Do a mass-deallocation of all the individual allocations
208
// that have occurred.
209
//
210
void PoolAllocator::popAll()
211
{
212
while (mStack.size() > 0)
213
pop();
214
}
215
216
void *PoolAllocator::allocate(size_t numBytes)
217
{
218
ASSERT(!mLocked);
219
220
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
221
//
222
// Just keep some interesting statistics.
223
//
224
++mNumCalls;
225
mTotalBytes += numBytes;
226
227
// If we are using guard blocks, all allocations are bracketed by
228
// them: [guardblock][allocation][guardblock]. numBytes is how
229
// much memory the caller asked for. allocationSize is the total
230
// size including guard blocks. In release build,
231
// kGuardBlockSize=0 and this all gets optimized away.
232
size_t allocationSize = Allocation::AllocationSize(numBytes) + mAlignment;
233
// Detect integer overflow.
234
if (allocationSize < numBytes)
235
return 0;
236
237
//
238
// Do the allocation, most likely case first, for efficiency.
239
// This step could be moved to be inline sometime.
240
//
241
if (allocationSize <= mPageSize - mCurrentPageOffset)
242
{
243
//
244
// Safe to allocate from mCurrentPageOffset.
245
//
246
unsigned char *memory = reinterpret_cast<unsigned char *>(mInUseList) + mCurrentPageOffset;
247
mCurrentPageOffset += allocationSize;
248
mCurrentPageOffset = (mCurrentPageOffset + mAlignmentMask) & ~mAlignmentMask;
249
250
return initializeAllocation(mInUseList, memory, numBytes);
251
}
252
253
if (allocationSize > mPageSize - mHeaderSkip)
254
{
255
//
256
// Do a multi-page allocation. Don't mix these with the others.
257
// The OS is efficient in allocating and freeing multiple pages.
258
//
259
size_t numBytesToAlloc = allocationSize + mHeaderSkip;
260
// Detect integer overflow.
261
if (numBytesToAlloc < allocationSize)
262
return 0;
263
264
Header *memory = reinterpret_cast<Header *>(::new char[numBytesToAlloc]);
265
if (memory == 0)
266
return 0;
267
268
// Use placement-new to initialize header
269
new (memory) Header(mInUseList, (numBytesToAlloc + mPageSize - 1) / mPageSize);
270
mInUseList = memory;
271
272
mCurrentPageOffset = mPageSize; // make next allocation come from a new page
273
274
// No guard blocks for multi-page allocations (yet)
275
void *unalignedPtr =
276
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(memory) + mHeaderSkip);
277
return std::align(mAlignment, numBytes, unalignedPtr, allocationSize);
278
}
279
unsigned char *newPageAddr =
280
static_cast<unsigned char *>(allocateNewPage(numBytes, allocationSize));
281
return initializeAllocation(mInUseList, newPageAddr, numBytes);
282
#else // !defined(ANGLE_DISABLE_POOL_ALLOC)
283
void *alloc = malloc(numBytes + mAlignmentMask);
284
mStack.back().push_back(alloc);
285
286
intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
287
intAlloc = (intAlloc + mAlignmentMask) & ~mAlignmentMask;
288
return reinterpret_cast<void *>(intAlloc);
289
#endif
290
}
291
292
#if !defined(ANGLE_DISABLE_POOL_ALLOC)
293
void *PoolAllocator::allocateNewPage(size_t numBytes, size_t allocationSize)
294
{
295
//
296
// Need a simple page to allocate from.
297
//
298
Header *memory;
299
if (mFreeList)
300
{
301
memory = mFreeList;
302
mFreeList = mFreeList->nextPage;
303
}
304
else
305
{
306
memory = reinterpret_cast<Header *>(::new char[mPageSize]);
307
if (memory == 0)
308
return 0;
309
}
310
// Use placement-new to initialize header
311
new (memory) Header(mInUseList, 1);
312
mInUseList = memory;
313
314
unsigned char *ret = reinterpret_cast<unsigned char *>(mInUseList) + mHeaderSkip;
315
mCurrentPageOffset = (mHeaderSkip + allocationSize + mAlignmentMask) & ~mAlignmentMask;
316
return ret;
317
}
318
#endif
319
320
void PoolAllocator::lock()
321
{
322
ASSERT(!mLocked);
323
mLocked = true;
324
}
325
326
void PoolAllocator::unlock()
327
{
328
ASSERT(mLocked);
329
mLocked = false;
330
}
331
332
//
333
// Check all allocations in a list for damage by calling check on each.
334
//
335
void Allocation::checkAllocList() const
336
{
337
for (const Allocation *alloc = this; alloc != 0; alloc = alloc->mPrevAlloc)
338
alloc->checkAlloc();
339
}
340
341
} // namespace angle
342
343