Edit

kc3-lang/angle/src/compiler/translator/PoolAlloc.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2016-12-12 14:42:19
    Hash : d7b1ab58
    Message : Fix up translator style. Using git cl format. BUG=angleproject:650 Change-Id: I7d3f98d2b0dcfb0a8de6c35327db74e55c28d761 Reviewed-on: https://chromium-review.googlesource.com/419059 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/PoolAlloc.cpp
  • //
    // 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();
    }