initial import
[vuplus_webkit] / Source / ThirdParty / ANGLE / src / compiler / 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/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 void 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
31 void 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
41 bool 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
50 void FreePoolIndex()
51 {
52     // Release the TLS index.
53     OS_FreeTLSIndex(PoolIndex);
54 }
55
56 TPoolAllocator& GetGlobalPoolAllocator()
57 {
58     TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
59
60     return *threadData->globalPoolAllocator;
61 }
62
63 void 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 //
74 TPoolAllocator::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
118 TPoolAllocator::~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
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 void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
153 {
154 #ifdef GUARD_BLOCKS
155     for (size_t x = 0; x < guardBlockSize; x++) {
156         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                     locText, size, data());
162             assert(0 && "PoolAlloc: Damage in guard block");
163         }
164     }
165 #endif
166 }
167
168
169 void TPoolAllocator::push()
170 {
171     tAllocState state = { currentPageOffset, inUseList };
172
173     stack.push_back(state);
174         
175     //
176     // Indicate there is no current page to allocate from.
177     //
178     currentPageOffset = pageSize;
179 }
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 void TPoolAllocator::pop()
189 {
190     if (stack.size() < 1)
191         return;
192
193     tHeader* page = stack.back().page;
194     currentPageOffset = stack.back().offset;
195
196     while (inUseList != page) {
197         // invoke destructor to free allocation list
198         inUseList->~tHeader();
199         
200         tHeader* nextInUse = inUseList->nextPage;
201         if (inUseList->pageCount > 1)
202             delete [] reinterpret_cast<char*>(inUseList);
203         else {
204             inUseList->nextPage = freeList;
205             freeList = inUseList;
206         }
207         inUseList = nextInUse;
208     }
209
210     stack.pop_back();
211 }
212
213 //
214 // Do a mass-deallocation of all the individual allocations
215 // that have occurred.
216 //
217 void TPoolAllocator::popAll()
218 {
219     while (stack.size() > 0)
220         pop();
221 }
222
223 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     size_t allocationSize = TAllocation::allocationSize(numBytes);
231     
232     //
233     // Just keep some interesting statistics.
234     //
235     ++numCalls;
236     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     if (currentPageOffset + allocationSize <= pageSize) {
243         //
244         // Safe to allocate from currentPageOffset.
245         //
246         unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
247         currentPageOffset += allocationSize;
248         currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
249
250         return initializeAllocation(inUseList, memory, numBytes);
251     }
252
253     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         size_t numBytesToAlloc = allocationSize + headerSkip;
259         tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
260         if (memory == 0)
261             return 0;
262
263         // Use placement-new to initialize header
264         new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
265         inUseList = memory;
266
267         currentPageOffset = pageSize;  // make next allocation come from a new page
268
269         // No guard blocks for multi-page allocations (yet)
270         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     if (freeList) {
278         memory = freeList;
279         freeList = freeList->nextPage;
280     } else {
281         memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
282         if (memory == 0)
283             return 0;
284     }
285
286     // Use placement-new to initialize header
287     new(memory) tHeader(inUseList, 1);
288     inUseList = memory;
289     
290     unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
291     currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
292
293     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 void TAllocation::checkAllocList() const
301 {
302     for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
303         alloc->check();
304 }