1// 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. 5// 6 7#include "compiler/PoolAlloc.h" 8 9#ifndef _MSC_VER 10#include <stdint.h> 11#endif 12#include <stdio.h> 13 14#include "compiler/InitializeGlobals.h" 15#include "compiler/osinclude.h" 16 17OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX; 18 19void InitializeGlobalPools() 20{ 21 TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); 22 if (globalPools) 23 return; 24 25 TThreadGlobalPools* threadData = new TThreadGlobalPools(); 26 threadData->globalPoolAllocator = 0; 27 28 OS_SetTLSValue(PoolIndex, threadData); 29} 30 31void FreeGlobalPools() 32{ 33 // Release the allocated memory for this thread. 34 TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); 35 if (!globalPools) 36 return; 37 38 delete globalPools; 39} 40 41bool InitializePoolIndex() 42{ 43 // Allocate a TLS index. 44 if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX) 45 return false; 46 47 return true; 48} 49 50void FreePoolIndex() 51{ 52 // Release the TLS index. 53 OS_FreeTLSIndex(PoolIndex); 54} 55 56TPoolAllocator& GetGlobalPoolAllocator() 57{ 58 TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); 59 60 return *threadData->globalPoolAllocator; 61} 62 63void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) 64{ 65 TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); 66 67 threadData->globalPoolAllocator = poolAllocator; 68} 69 70// 71// Implement the functionality of the TPoolAllocator class, which 72// is documented in PoolAlloc.h. 73// 74TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : 75 pageSize(growthIncrement), 76 alignment(allocationAlignment), 77 freeList(0), 78 inUseList(0), 79 numCalls(0), 80 totalBytes(0) 81{ 82 // 83 // Don't allow page sizes we know are smaller than all common 84 // OS page sizes. 85 // 86 if (pageSize < 4*1024) 87 pageSize = 4*1024; 88 89 // 90 // A large currentPageOffset indicates a new page needs to 91 // be obtained to allocate memory. 92 // 93 currentPageOffset = pageSize; 94 95 // 96 // Adjust alignment to be at least pointer aligned and 97 // power of 2. 98 // 99 size_t minAlign = sizeof(void*); 100 alignment &= ~(minAlign - 1); 101 if (alignment < minAlign) 102 alignment = minAlign; 103 size_t a = 1; 104 while (a < alignment) 105 a <<= 1; 106 alignment = a; 107 alignmentMask = a - 1; 108 109 // 110 // Align header skip 111 // 112 headerSkip = minAlign; 113 if (headerSkip < sizeof(tHeader)) { 114 headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask; 115 } 116} 117 118TPoolAllocator::~TPoolAllocator() 119{ 120 while (inUseList) { 121 tHeader* next = inUseList->nextPage; 122 inUseList->~tHeader(); 123 delete [] reinterpret_cast<char*>(inUseList); 124 inUseList = next; 125 } 126 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. 130 // 131 while (freeList) { 132 tHeader* next = freeList->nextPage; 133 delete [] reinterpret_cast<char*>(freeList); 134 freeList = next; 135 } 136} 137 138// Support MSVC++ 6.0 139const unsigned char TAllocation::guardBlockBeginVal = 0xfb; 140const unsigned char TAllocation::guardBlockEndVal = 0xfe; 141const unsigned char TAllocation::userDataFill = 0xcd; 142 143#ifdef GUARD_BLOCKS 144 const size_t TAllocation::guardBlockSize = 16; 145#else 146 const size_t TAllocation::guardBlockSize = 0; 147#endif 148 149// 150// Check a single guard block for damage 151// 152void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const 153{ 154 for (size_t x = 0; x < guardBlockSize; x++) { 155 if (blockMem[x] != val) { 156 char assertMsg[80]; 157 158 // We don't print the assert message. It's here just to be helpful. 159 sprintf(assertMsg, "PoolAlloc: Damage %s %u byte allocation at 0x%p\n", 160 locText, size, data()); 161 assert(0 && "PoolAlloc: Damage in guard block"); 162 } 163 } 164} 165 166 167void TPoolAllocator::push() 168{ 169 tAllocState state = { currentPageOffset, inUseList }; 170 171 stack.push_back(state); 172 173 // 174 // Indicate there is no current page to allocate from. 175 // 176 currentPageOffset = pageSize; 177} 178 179// 180// Do a mass-deallocation of all the individual allocations 181// that have occurred since the last push(), or since the 182// last pop(), or since the object's creation. 183// 184// The deallocated pages are saved for future allocations. 185// 186void TPoolAllocator::pop() 187{ 188 if (stack.size() < 1) 189 return; 190 191 tHeader* page = stack.back().page; 192 currentPageOffset = stack.back().offset; 193 194 while (inUseList != page) { 195 // invoke destructor to free allocation list 196 inUseList->~tHeader(); 197 198 tHeader* nextInUse = inUseList->nextPage; 199 if (inUseList->pageCount > 1) 200 delete [] reinterpret_cast<char*>(inUseList); 201 else { 202 inUseList->nextPage = freeList; 203 freeList = inUseList; 204 } 205 inUseList = nextInUse; 206 } 207 208 stack.pop_back(); 209} 210 211// 212// Do a mass-deallocation of all the individual allocations 213// that have occurred. 214// 215void TPoolAllocator::popAll() 216{ 217 while (stack.size() > 0) 218 pop(); 219} 220 221void* TPoolAllocator::allocate(size_t numBytes) 222{ 223 // If we are using guard blocks, all allocations are bracketed by 224 // them: [guardblock][allocation][guardblock]. numBytes is how 225 // much memory the caller asked for. allocationSize is the total 226 // size including guard blocks. In release build, 227 // guardBlockSize=0 and this all gets optimized away. 228 size_t allocationSize = TAllocation::allocationSize(numBytes); 229 230 // 231 // Just keep some interesting statistics. 232 // 233 ++numCalls; 234 totalBytes += numBytes; 235 236 // 237 // Do the allocation, most likely case first, for efficiency. 238 // This step could be moved to be inline sometime. 239 // 240 if (currentPageOffset + allocationSize <= pageSize) { 241 // 242 // Safe to allocate from currentPageOffset. 243 // 244 unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset; 245 currentPageOffset += allocationSize; 246 currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask; 247 248 return initializeAllocation(inUseList, memory, numBytes); 249 } 250 251 if (allocationSize + headerSkip > pageSize) { 252 // 253 // Do a multi-page allocation. Don't mix these with the others. 254 // The OS is efficient and allocating and free-ing multiple pages. 255 // 256 size_t numBytesToAlloc = allocationSize + headerSkip; 257 tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]); 258 if (memory == 0) 259 return 0; 260 261 // Use placement-new to initialize header 262 new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); 263 inUseList = memory; 264 265 currentPageOffset = pageSize; // make next allocation come from a new page 266 267 // No guard blocks for multi-page allocations (yet) 268 return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip); 269 } 270 271 // 272 // Need a simple page to allocate from. 273 // 274 tHeader* memory; 275 if (freeList) { 276 memory = freeList; 277 freeList = freeList->nextPage; 278 } else { 279 memory = reinterpret_cast<tHeader*>(::new char[pageSize]); 280 if (memory == 0) 281 return 0; 282 } 283 284 // Use placement-new to initialize header 285 new(memory) tHeader(inUseList, 1); 286 inUseList = memory; 287 288 unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip; 289 currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; 290 291 return initializeAllocation(inUseList, ret, numBytes); 292} 293 294 295// 296// Check all allocations in a list for damage by calling check on each. 297// 298void TAllocation::checkAllocList() const 299{ 300 for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) 301 alloc->check(); 302}