summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/compiler/translator/PoolAlloc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/compiler/translator/PoolAlloc.cpp')
-rwxr-xr-xgfx/angle/src/compiler/translator/PoolAlloc.cpp347
1 files changed, 347 insertions, 0 deletions
diff --git a/gfx/angle/src/compiler/translator/PoolAlloc.cpp b/gfx/angle/src/compiler/translator/PoolAlloc.cpp
new file mode 100755
index 000000000..3b44afe33
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/PoolAlloc.cpp
@@ -0,0 +1,347 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/PoolAlloc.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "common/platform.h"
+#include "common/tls.h"
+#include "compiler/translator/InitializeGlobals.h"
+
+TLSIndex PoolIndex = TLS_INVALID_INDEX;
+
+bool InitializePoolIndex()
+{
+ assert(PoolIndex == TLS_INVALID_INDEX);
+
+ PoolIndex = CreateTLSIndex();
+ return PoolIndex != TLS_INVALID_INDEX;
+}
+
+void FreePoolIndex()
+{
+ assert(PoolIndex != TLS_INVALID_INDEX);
+
+ DestroyTLSIndex(PoolIndex);
+ PoolIndex = TLS_INVALID_INDEX;
+}
+
+TPoolAllocator* GetGlobalPoolAllocator()
+{
+ assert(PoolIndex != TLS_INVALID_INDEX);
+ return static_cast<TPoolAllocator*>(GetTLSValue(PoolIndex));
+}
+
+void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
+{
+ assert(PoolIndex != TLS_INVALID_INDEX);
+ SetTLSValue(PoolIndex, poolAllocator);
+}
+
+//
+// Implement the functionality of the TPoolAllocator class, which
+// is documented in PoolAlloc.h.
+//
+TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment)
+ : alignment(allocationAlignment),
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ pageSize(growthIncrement),
+ freeList(0),
+ inUseList(0),
+ numCalls(0),
+ totalBytes(0),
+#endif
+ mLocked(false)
+{
+ //
+ // Adjust alignment to be at least pointer aligned and
+ // power of 2.
+ //
+ size_t minAlign = sizeof(void*);
+ alignment &= ~(minAlign - 1);
+ if (alignment < minAlign)
+ alignment = minAlign;
+ size_t a = 1;
+ while (a < alignment)
+ a <<= 1;
+ alignment = a;
+ alignmentMask = a - 1;
+
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ //
+ // Don't allow page sizes we know are smaller than all common
+ // OS page sizes.
+ //
+ if (pageSize < 4 * 1024)
+ pageSize = 4 * 1024;
+
+ //
+ // A large currentPageOffset indicates a new page needs to
+ // be obtained to allocate memory.
+ //
+ currentPageOffset = pageSize;
+
+ //
+ // Align header skip
+ //
+ headerSkip = minAlign;
+ if (headerSkip < sizeof(tHeader)) {
+ headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
+ }
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ mStack.push_back({});
+#endif
+}
+
+TPoolAllocator::~TPoolAllocator()
+{
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ while (inUseList) {
+ tHeader* next = inUseList->nextPage;
+ inUseList->~tHeader();
+ delete [] reinterpret_cast<char*>(inUseList);
+ inUseList = next;
+ }
+
+ // We should not check the guard blocks
+ // here, because we did it already when the block was
+ // placed into the free list.
+ //
+ while (freeList) {
+ tHeader* next = freeList->nextPage;
+ delete [] reinterpret_cast<char*>(freeList);
+ freeList = next;
+ }
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ for (auto &allocs : mStack)
+ {
+ for (auto alloc : allocs)
+ {
+ free(alloc);
+ }
+ }
+ mStack.clear();
+#endif
+}
+
+// Support MSVC++ 6.0
+const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
+const unsigned char TAllocation::guardBlockEndVal = 0xfe;
+const unsigned char TAllocation::userDataFill = 0xcd;
+
+#ifdef GUARD_BLOCKS
+ const size_t TAllocation::guardBlockSize = 16;
+#else
+ const size_t TAllocation::guardBlockSize = 0;
+#endif
+
+//
+// Check a single guard block for damage
+//
+void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
+{
+#ifdef GUARD_BLOCKS
+ for (size_t x = 0; x < guardBlockSize; x++) {
+ if (blockMem[x] != val) {
+ char assertMsg[80];
+
+ // We don't print the assert message. It's here just to be helpful.
+#if defined(_MSC_VER)
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n",
+ locText, size, data());
+#else
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
+ locText, size, data());
+#endif
+ assert(0 && "PoolAlloc: Damage in guard block");
+ }
+ }
+#endif
+}
+
+
+void TPoolAllocator::push()
+{
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ tAllocState state = { currentPageOffset, inUseList };
+
+ mStack.push_back(state);
+
+ //
+ // Indicate there is no current page to allocate from.
+ //
+ currentPageOffset = pageSize;
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ mStack.push_back({});
+#endif
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred since the last push(), or since the
+// last pop(), or since the object's creation.
+//
+// The deallocated pages are saved for future allocations.
+//
+void TPoolAllocator::pop()
+{
+ if (mStack.size() < 1)
+ return;
+
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ tHeader *page = mStack.back().page;
+ currentPageOffset = mStack.back().offset;
+
+ while (inUseList != page) {
+ // invoke destructor to free allocation list
+ inUseList->~tHeader();
+
+ tHeader* nextInUse = inUseList->nextPage;
+ if (inUseList->pageCount > 1)
+ delete [] reinterpret_cast<char*>(inUseList);
+ else {
+ inUseList->nextPage = freeList;
+ freeList = inUseList;
+ }
+ inUseList = nextInUse;
+ }
+
+ mStack.pop_back();
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ for (auto &alloc : mStack.back())
+ {
+ free(alloc);
+ }
+ mStack.pop_back();
+#endif
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred.
+//
+void TPoolAllocator::popAll()
+{
+ while (mStack.size() > 0)
+ pop();
+}
+
+void* TPoolAllocator::allocate(size_t numBytes)
+{
+ ASSERT(!mLocked);
+
+#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ //
+ // Just keep some interesting statistics.
+ //
+ ++numCalls;
+ totalBytes += numBytes;
+
+ // If we are using guard blocks, all allocations are bracketed by
+ // them: [guardblock][allocation][guardblock]. numBytes is how
+ // much memory the caller asked for. allocationSize is the total
+ // size including guard blocks. In release build,
+ // guardBlockSize=0 and this all gets optimized away.
+ size_t allocationSize = TAllocation::allocationSize(numBytes);
+ // Detect integer overflow.
+ if (allocationSize < numBytes)
+ return 0;
+
+ //
+ // Do the allocation, most likely case first, for efficiency.
+ // This step could be moved to be inline sometime.
+ //
+ if (allocationSize <= pageSize - currentPageOffset) {
+ //
+ // Safe to allocate from currentPageOffset.
+ //
+ unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
+ currentPageOffset += allocationSize;
+ currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, memory, numBytes);
+ }
+
+ if (allocationSize > pageSize - headerSkip) {
+ //
+ // Do a multi-page allocation. Don't mix these with the others.
+ // The OS is efficient and allocating and free-ing multiple pages.
+ //
+ size_t numBytesToAlloc = allocationSize + headerSkip;
+ // Detect integer overflow.
+ if (numBytesToAlloc < allocationSize)
+ return 0;
+
+ tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
+ if (memory == 0)
+ return 0;
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
+ inUseList = memory;
+
+ currentPageOffset = pageSize; // make next allocation come from a new page
+
+ // No guard blocks for multi-page allocations (yet)
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
+ }
+
+ //
+ // Need a simple page to allocate from.
+ //
+ tHeader* memory;
+ if (freeList) {
+ memory = freeList;
+ freeList = freeList->nextPage;
+ } else {
+ memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
+ if (memory == 0)
+ return 0;
+ }
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, 1);
+ inUseList = memory;
+
+ unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
+ currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, ret, numBytes);
+#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
+ void *alloc = malloc(numBytes + alignmentMask);
+ mStack.back().push_back(alloc);
+
+ intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
+ intAlloc = (intAlloc + alignmentMask) & ~alignmentMask;
+ return reinterpret_cast<void *>(intAlloc);
+#endif
+}
+
+void TPoolAllocator::lock()
+{
+ ASSERT(!mLocked);
+ mLocked = true;
+}
+
+void TPoolAllocator::unlock()
+{
+ ASSERT(mLocked);
+ mLocked = false;
+}
+
+//
+// Check all allocations in a list for damage by calling check on each.
+//
+void TAllocation::checkAllocList() const
+{
+ for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
+ alloc->check();
+}