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