2 // Copyright (c) 2002-2010 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.
7 #include "compiler/translator/PoolAlloc.h"
9 #include "compiler/translator/InitializeGlobals.h"
11 #include "common/platform.h"
12 #include "common/angleutils.h"
13 #include "common/tls.h"
19 TLSIndex PoolIndex = TLS_INVALID_INDEX;
21 bool InitializePoolIndex()
23 assert(PoolIndex == TLS_INVALID_INDEX);
25 PoolIndex = CreateTLSIndex();
26 return PoolIndex != TLS_INVALID_INDEX;
31 assert(PoolIndex != TLS_INVALID_INDEX);
33 DestroyTLSIndex(PoolIndex);
34 PoolIndex = TLS_INVALID_INDEX;
37 TPoolAllocator* GetGlobalPoolAllocator()
39 assert(PoolIndex != TLS_INVALID_INDEX);
40 return static_cast<TPoolAllocator*>(GetTLSValue(PoolIndex));
43 void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
45 assert(PoolIndex != TLS_INVALID_INDEX);
46 SetTLSValue(PoolIndex, poolAllocator);
50 // Implement the functionality of the TPoolAllocator class, which
51 // is documented in PoolAlloc.h.
53 TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
54 pageSize(growthIncrement),
55 alignment(allocationAlignment),
62 // Don't allow page sizes we know are smaller than all common
65 if (pageSize < 4*1024)
69 // A large currentPageOffset indicates a new page needs to
70 // be obtained to allocate memory.
72 currentPageOffset = pageSize;
75 // Adjust alignment to be at least pointer aligned and
78 size_t minAlign = sizeof(void*);
79 alignment &= ~(minAlign - 1);
80 if (alignment < minAlign)
86 alignmentMask = a - 1;
91 headerSkip = minAlign;
92 if (headerSkip < sizeof(tHeader)) {
93 headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
97 TPoolAllocator::~TPoolAllocator()
100 tHeader* next = inUseList->nextPage;
101 inUseList->~tHeader();
102 delete [] reinterpret_cast<char*>(inUseList);
106 // We should not check the guard blocks
107 // here, because we did it already when the block was
108 // placed into the free list.
111 tHeader* next = freeList->nextPage;
112 delete [] reinterpret_cast<char*>(freeList);
117 // Support MSVC++ 6.0
118 const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
119 const unsigned char TAllocation::guardBlockEndVal = 0xfe;
120 const unsigned char TAllocation::userDataFill = 0xcd;
123 const size_t TAllocation::guardBlockSize = 16;
125 const size_t TAllocation::guardBlockSize = 0;
129 // Check a single guard block for damage
131 void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
134 for (size_t x = 0; x < guardBlockSize; x++) {
135 if (blockMem[x] != val) {
138 // We don't print the assert message. It's here just to be helpful.
139 #if defined(_MSC_VER)
140 snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n",
141 locText, size, data());
143 snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
144 locText, size, data());
146 assert(0 && "PoolAlloc: Damage in guard block");
153 void TPoolAllocator::push()
155 tAllocState state = { currentPageOffset, inUseList };
157 stack.push_back(state);
160 // Indicate there is no current page to allocate from.
162 currentPageOffset = pageSize;
166 // Do a mass-deallocation of all the individual allocations
167 // that have occurred since the last push(), or since the
168 // last pop(), or since the object's creation.
170 // The deallocated pages are saved for future allocations.
172 void TPoolAllocator::pop()
174 if (stack.size() < 1)
177 tHeader* page = stack.back().page;
178 currentPageOffset = stack.back().offset;
180 while (inUseList != page) {
181 // invoke destructor to free allocation list
182 inUseList->~tHeader();
184 tHeader* nextInUse = inUseList->nextPage;
185 if (inUseList->pageCount > 1)
186 delete [] reinterpret_cast<char*>(inUseList);
188 inUseList->nextPage = freeList;
189 freeList = inUseList;
191 inUseList = nextInUse;
198 // Do a mass-deallocation of all the individual allocations
199 // that have occurred.
201 void TPoolAllocator::popAll()
203 while (stack.size() > 0)
207 void* TPoolAllocator::allocate(size_t numBytes)
210 // Just keep some interesting statistics.
213 totalBytes += numBytes;
215 // If we are using guard blocks, all allocations are bracketed by
216 // them: [guardblock][allocation][guardblock]. numBytes is how
217 // much memory the caller asked for. allocationSize is the total
218 // size including guard blocks. In release build,
219 // guardBlockSize=0 and this all gets optimized away.
220 size_t allocationSize = TAllocation::allocationSize(numBytes);
221 // Detect integer overflow.
222 if (allocationSize < numBytes)
226 // Do the allocation, most likely case first, for efficiency.
227 // This step could be moved to be inline sometime.
229 if (allocationSize <= pageSize - currentPageOffset) {
231 // Safe to allocate from currentPageOffset.
233 unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
234 currentPageOffset += allocationSize;
235 currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
237 return initializeAllocation(inUseList, memory, numBytes);
240 if (allocationSize > pageSize - headerSkip) {
242 // Do a multi-page allocation. Don't mix these with the others.
243 // The OS is efficient and allocating and free-ing multiple pages.
245 size_t numBytesToAlloc = allocationSize + headerSkip;
246 // Detect integer overflow.
247 if (numBytesToAlloc < allocationSize)
250 tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
254 // Use placement-new to initialize header
255 new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
258 currentPageOffset = pageSize; // make next allocation come from a new page
260 // No guard blocks for multi-page allocations (yet)
261 return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
265 // Need a simple page to allocate from.
270 freeList = freeList->nextPage;
272 memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
277 // Use placement-new to initialize header
278 new(memory) tHeader(inUseList, 1);
281 unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
282 currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
284 return initializeAllocation(inUseList, ret, numBytes);
289 // Check all allocations in a list for damage by calling check on each.
291 void TAllocation::checkAllocList() const
293 for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)