Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / PoolAlloc.cpp
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/translator/PoolAlloc.h"
8
9 #include "compiler/translator/InitializeGlobals.h"
10
11 #include "common/platform.h"
12 #include "common/angleutils.h"
13 #include "common/tls.h"
14
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <assert.h>
18
19 TLSIndex PoolIndex = TLS_INVALID_INDEX;
20
21 bool InitializePoolIndex()
22 {
23     assert(PoolIndex == TLS_INVALID_INDEX);
24
25     PoolIndex = CreateTLSIndex();
26     return PoolIndex != TLS_INVALID_INDEX;
27 }
28
29 void FreePoolIndex()
30 {
31     assert(PoolIndex != TLS_INVALID_INDEX);
32
33     DestroyTLSIndex(PoolIndex);
34     PoolIndex = TLS_INVALID_INDEX;
35 }
36
37 TPoolAllocator* GetGlobalPoolAllocator()
38 {
39     assert(PoolIndex != TLS_INVALID_INDEX);
40     return static_cast<TPoolAllocator*>(GetTLSValue(PoolIndex));
41 }
42
43 void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
44 {
45     assert(PoolIndex != TLS_INVALID_INDEX);
46     SetTLSValue(PoolIndex, poolAllocator);
47 }
48
49 //
50 // Implement the functionality of the TPoolAllocator class, which
51 // is documented in PoolAlloc.h.
52 //
53 TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : 
54     pageSize(growthIncrement),
55     alignment(allocationAlignment),
56     freeList(0),
57     inUseList(0),
58     numCalls(0),
59     totalBytes(0)
60 {
61     //
62     // Don't allow page sizes we know are smaller than all common
63     // OS page sizes.
64     //
65     if (pageSize < 4*1024)
66         pageSize = 4*1024;
67
68     //
69     // A large currentPageOffset indicates a new page needs to
70     // be obtained to allocate memory.
71     //
72     currentPageOffset = pageSize;
73
74     //
75     // Adjust alignment to be at least pointer aligned and
76     // power of 2.
77     //
78     size_t minAlign = sizeof(void*);
79     alignment &= ~(minAlign - 1);
80     if (alignment < minAlign)
81         alignment = minAlign;
82     size_t a = 1;
83     while (a < alignment)
84         a <<= 1;
85     alignment = a;
86     alignmentMask = a - 1;
87
88     //
89     // Align header skip
90     //
91     headerSkip = minAlign;
92     if (headerSkip < sizeof(tHeader)) {
93         headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
94     }
95 }
96
97 TPoolAllocator::~TPoolAllocator()
98 {
99     while (inUseList) {
100         tHeader* next = inUseList->nextPage;
101         inUseList->~tHeader();
102         delete [] reinterpret_cast<char*>(inUseList);
103         inUseList = next;
104     }
105
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.
109     //
110     while (freeList) {
111         tHeader* next = freeList->nextPage;
112         delete [] reinterpret_cast<char*>(freeList);
113         freeList = next;
114     }
115 }
116
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;
121
122 #ifdef GUARD_BLOCKS
123     const size_t TAllocation::guardBlockSize = 16;
124 #else
125     const size_t TAllocation::guardBlockSize = 0;
126 #endif
127
128 //
129 // Check a single guard block for damage
130 //
131 void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
132 {
133 #ifdef GUARD_BLOCKS
134     for (size_t x = 0; x < guardBlockSize; x++) {
135         if (blockMem[x] != val) {
136             char assertMsg[80];
137
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());
142 #else
143             snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
144                     locText, size, data());
145 #endif
146             assert(0 && "PoolAlloc: Damage in guard block");
147         }
148     }
149 #endif
150 }
151
152
153 void TPoolAllocator::push()
154 {
155     tAllocState state = { currentPageOffset, inUseList };
156
157     stack.push_back(state);
158         
159     //
160     // Indicate there is no current page to allocate from.
161     //
162     currentPageOffset = pageSize;
163 }
164
165 //
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.
169 //
170 // The deallocated pages are saved for future allocations.
171 //
172 void TPoolAllocator::pop()
173 {
174     if (stack.size() < 1)
175         return;
176
177     tHeader* page = stack.back().page;
178     currentPageOffset = stack.back().offset;
179
180     while (inUseList != page) {
181         // invoke destructor to free allocation list
182         inUseList->~tHeader();
183         
184         tHeader* nextInUse = inUseList->nextPage;
185         if (inUseList->pageCount > 1)
186             delete [] reinterpret_cast<char*>(inUseList);
187         else {
188             inUseList->nextPage = freeList;
189             freeList = inUseList;
190         }
191         inUseList = nextInUse;
192     }
193
194     stack.pop_back();
195 }
196
197 //
198 // Do a mass-deallocation of all the individual allocations
199 // that have occurred.
200 //
201 void TPoolAllocator::popAll()
202 {
203     while (stack.size() > 0)
204         pop();
205 }
206
207 void* TPoolAllocator::allocate(size_t numBytes)
208 {
209     //
210     // Just keep some interesting statistics.
211     //
212     ++numCalls;
213     totalBytes += numBytes;
214
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)
223         return 0;
224
225     //
226     // Do the allocation, most likely case first, for efficiency.
227     // This step could be moved to be inline sometime.
228     //
229     if (allocationSize <= pageSize - currentPageOffset) {
230         //
231         // Safe to allocate from currentPageOffset.
232         //
233         unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
234         currentPageOffset += allocationSize;
235         currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
236
237         return initializeAllocation(inUseList, memory, numBytes);
238     }
239
240     if (allocationSize > pageSize - headerSkip) {
241         //
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.
244         //
245         size_t numBytesToAlloc = allocationSize + headerSkip;
246         // Detect integer overflow.
247         if (numBytesToAlloc < allocationSize)
248             return 0;
249
250         tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
251         if (memory == 0)
252             return 0;
253
254         // Use placement-new to initialize header
255         new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
256         inUseList = memory;
257
258         currentPageOffset = pageSize;  // make next allocation come from a new page
259
260         // No guard blocks for multi-page allocations (yet)
261         return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
262     }
263
264     //
265     // Need a simple page to allocate from.
266     //
267     tHeader* memory;
268     if (freeList) {
269         memory = freeList;
270         freeList = freeList->nextPage;
271     } else {
272         memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
273         if (memory == 0)
274             return 0;
275     }
276
277     // Use placement-new to initialize header
278     new(memory) tHeader(inUseList, 1);
279     inUseList = memory;
280     
281     unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
282     currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
283
284     return initializeAllocation(inUseList, ret, numBytes);
285 }
286
287
288 //
289 // Check all allocations in a list for damage by calling check on each.
290 //
291 void TAllocation::checkAllocList() const
292 {
293     for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
294         alloc->check();
295 }