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/PoolAlloc.h"
14 #include "compiler/InitializeGlobals.h"
15 #include "compiler/osinclude.h"
17 OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX;
19 void InitializeGlobalPools()
21 TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
25 TThreadGlobalPools* threadData = new TThreadGlobalPools();
26 threadData->globalPoolAllocator = 0;
28 OS_SetTLSValue(PoolIndex, threadData);
31 void FreeGlobalPools()
33 // Release the allocated memory for this thread.
34 TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
41 bool InitializePoolIndex()
43 // Allocate a TLS index.
44 if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX)
52 // Release the TLS index.
53 OS_FreeTLSIndex(PoolIndex);
56 TPoolAllocator& GetGlobalPoolAllocator()
58 TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
60 return *threadData->globalPoolAllocator;
63 void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
65 TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
67 threadData->globalPoolAllocator = poolAllocator;
71 // Implement the functionality of the TPoolAllocator class, which
72 // is documented in PoolAlloc.h.
74 TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
75 pageSize(growthIncrement),
76 alignment(allocationAlignment),
83 // Don't allow page sizes we know are smaller than all common
86 if (pageSize < 4*1024)
90 // A large currentPageOffset indicates a new page needs to
91 // be obtained to allocate memory.
93 currentPageOffset = pageSize;
96 // Adjust alignment to be at least pointer aligned and
99 size_t minAlign = sizeof(void*);
100 alignment &= ~(minAlign - 1);
101 if (alignment < minAlign)
102 alignment = minAlign;
104 while (a < alignment)
107 alignmentMask = a - 1;
112 headerSkip = minAlign;
113 if (headerSkip < sizeof(tHeader)) {
114 headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
118 TPoolAllocator::~TPoolAllocator()
121 tHeader* next = inUseList->nextPage;
122 inUseList->~tHeader();
123 delete [] reinterpret_cast<char*>(inUseList);
127 // We should not check the guard blocks
128 // here, because we did it already when the block was
129 // placed into the free list.
132 tHeader* next = freeList->nextPage;
133 delete [] reinterpret_cast<char*>(freeList);
138 // Support MSVC++ 6.0
139 const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
140 const unsigned char TAllocation::guardBlockEndVal = 0xfe;
141 const unsigned char TAllocation::userDataFill = 0xcd;
144 const size_t TAllocation::guardBlockSize = 16;
146 const size_t TAllocation::guardBlockSize = 0;
150 // Check a single guard block for damage
152 void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
155 for (size_t x = 0; x < guardBlockSize; x++) {
156 if (blockMem[x] != val) {
159 // We don't print the assert message. It's here just to be helpful.
160 sprintf(assertMsg, "PoolAlloc: Damage %s %lu byte allocation at 0x%p\n",
161 locText, size, data());
162 assert(0 && "PoolAlloc: Damage in guard block");
169 void TPoolAllocator::push()
171 tAllocState state = { currentPageOffset, inUseList };
173 stack.push_back(state);
176 // Indicate there is no current page to allocate from.
178 currentPageOffset = pageSize;
182 // Do a mass-deallocation of all the individual allocations
183 // that have occurred since the last push(), or since the
184 // last pop(), or since the object's creation.
186 // The deallocated pages are saved for future allocations.
188 void TPoolAllocator::pop()
190 if (stack.size() < 1)
193 tHeader* page = stack.back().page;
194 currentPageOffset = stack.back().offset;
196 while (inUseList != page) {
197 // invoke destructor to free allocation list
198 inUseList->~tHeader();
200 tHeader* nextInUse = inUseList->nextPage;
201 if (inUseList->pageCount > 1)
202 delete [] reinterpret_cast<char*>(inUseList);
204 inUseList->nextPage = freeList;
205 freeList = inUseList;
207 inUseList = nextInUse;
214 // Do a mass-deallocation of all the individual allocations
215 // that have occurred.
217 void TPoolAllocator::popAll()
219 while (stack.size() > 0)
223 void* TPoolAllocator::allocate(size_t numBytes)
225 // If we are using guard blocks, all allocations are bracketed by
226 // them: [guardblock][allocation][guardblock]. numBytes is how
227 // much memory the caller asked for. allocationSize is the total
228 // size including guard blocks. In release build,
229 // guardBlockSize=0 and this all gets optimized away.
230 size_t allocationSize = TAllocation::allocationSize(numBytes);
233 // Just keep some interesting statistics.
236 totalBytes += numBytes;
239 // Do the allocation, most likely case first, for efficiency.
240 // This step could be moved to be inline sometime.
242 if (currentPageOffset + allocationSize <= pageSize) {
244 // Safe to allocate from currentPageOffset.
246 unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
247 currentPageOffset += allocationSize;
248 currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
250 return initializeAllocation(inUseList, memory, numBytes);
253 if (allocationSize + headerSkip > pageSize) {
255 // Do a multi-page allocation. Don't mix these with the others.
256 // The OS is efficient and allocating and free-ing multiple pages.
258 size_t numBytesToAlloc = allocationSize + headerSkip;
259 tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
263 // Use placement-new to initialize header
264 new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
267 currentPageOffset = pageSize; // make next allocation come from a new page
269 // No guard blocks for multi-page allocations (yet)
270 return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
274 // Need a simple page to allocate from.
279 freeList = freeList->nextPage;
281 memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
286 // Use placement-new to initialize header
287 new(memory) tHeader(inUseList, 1);
290 unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
291 currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
293 return initializeAllocation(inUseList, ret, numBytes);
298 // Check all allocations in a list for damage by calling check on each.
300 void TAllocation::checkAllocList() const
302 for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)