Edit

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

Branch :

  • Show log

    Commit

  • Author : Rafael Cintron
    Date : 2018-06-20 18:08:04
    Hash : 05a449a7
    Message : Replace reinterpret_cast with safer or no cast When casting types to one another in C++, the weaker the cast, the better. This change replaces instances of reinterpret_cast with static_cast or no cast where it safe and correct to do so. BUG=angleproject:2683 Change-Id: I99c9033614a65282ae1d78cf0f4b80fabd75877a Reviewed-on: https://chromium-review.googlesource.com/1109396 Commit-Queue: Rafael Cintron <rafael.cintron@microsoft.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/PoolAlloc.h
  • //
    // 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.
    //
    
    #ifndef COMPILER_TRANSLATOR_POOLALLOC_H_
    #define COMPILER_TRANSLATOR_POOLALLOC_H_
    
    #ifdef _DEBUG
    #define GUARD_BLOCKS  // define to enable guard block sanity checking
    #endif
    
    //
    // This header defines an allocator that can be used to efficiently
    // allocate a large number of small requests for heap memory, with the
    // intention that they are not individually deallocated, but rather
    // collectively deallocated at one time.
    //
    // This simultaneously
    //
    // * Makes each individual allocation much more efficient; the
    //     typical allocation is trivial.
    // * Completely avoids the cost of doing individual deallocation.
    // * Saves the trouble of tracking down and plugging a large class of leaks.
    //
    // Individual classes can use this allocator by supplying their own
    // new and delete methods.
    //
    // STL containers can use this allocator by using the pool_allocator
    // class as the allocator (second) template argument.
    //
    
    #include <stddef.h>
    #include <string.h>
    #include <vector>
    
    // If we are using guard blocks, we must track each indivual
    // allocation.  If we aren't using guard blocks, these
    // never get instantiated, so won't have any impact.
    //
    
    class TAllocation
    {
      public:
        TAllocation(size_t size, unsigned char *mem, TAllocation *prev = 0)
            : size(size), mem(mem), prevAlloc(prev)
        {
    // Allocations are bracketed:
    //    [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
    // This would be cleaner with if (guardBlockSize)..., but that
    // makes the compiler print warnings about 0 length memsets,
    // even with the if() protecting them.
    #ifdef GUARD_BLOCKS
            memset(preGuard(), guardBlockBeginVal, guardBlockSize);
            memset(data(), userDataFill, size);
            memset(postGuard(), guardBlockEndVal, guardBlockSize);
    #endif
        }
    
        void check() const
        {
            checkGuardBlock(preGuard(), guardBlockBeginVal, "before");
            checkGuardBlock(postGuard(), guardBlockEndVal, "after");
        }
    
        void checkAllocList() const;
    
        // Return total size needed to accomodate user buffer of 'size',
        // plus our tracking data.
        inline static size_t allocationSize(size_t size)
        {
            return size + 2 * guardBlockSize + headerSize();
        }
    
        // Offset from surrounding buffer to get to user data buffer.
        inline static unsigned char *offsetAllocation(unsigned char *m)
        {
            return m + guardBlockSize + headerSize();
        }
    
      private:
        void checkGuardBlock(unsigned char *blockMem, unsigned char val, const char *locText) const;
    
        // Find offsets to pre and post guard blocks, and user data buffer
        unsigned char *preGuard() const { return mem + headerSize(); }
        unsigned char *data() const { return preGuard() + guardBlockSize; }
        unsigned char *postGuard() const { return data() + size; }
    
        size_t size;             // size of the user data area
        unsigned char *mem;      // beginning of our allocation (pts to header)
        TAllocation *prevAlloc;  // prior allocation in the chain
    
        // Support MSVC++ 6.0
        const static unsigned char guardBlockBeginVal;
        const static unsigned char guardBlockEndVal;
        const static unsigned char userDataFill;
    
        const static size_t guardBlockSize;
    #ifdef GUARD_BLOCKS
        inline static size_t headerSize() { return sizeof(TAllocation); }
    #else
        inline static size_t headerSize() { return 0; }
    #endif
    };
    
    //
    // There are several stacks.  One is to track the pushing and popping
    // of the user, and not yet implemented.  The others are simply a
    // repositories of free pages or used pages.
    //
    // Page stacks are linked together with a simple header at the beginning
    // of each allocation obtained from the underlying OS.  Multi-page allocations
    // are returned to the OS.  Individual page allocations are kept for future
    // re-use.
    //
    // The "page size" used is not, nor must it match, the underlying OS
    // page size.  But, having it be about that size or equal to a set of
    // pages is likely most optimal.
    //
    class TPoolAllocator
    {
      public:
        TPoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = 16);
    
        //
        // Don't call the destructor just to free up the memory, call pop()
        //
        ~TPoolAllocator();
    
        //
        // Call push() to establish a new place to pop memory too.  Does not
        // have to be called to get things started.
        //
        void push();
    
        //
        // Call pop() to free all memory allocated since the last call to push(),
        // or if no last call to push, frees all memory since first allocation.
        //
        void pop();
    
        //
        // Call popAll() to free all memory allocated.
        //
        void popAll();
    
        //
        // Call allocate() to actually acquire memory.  Returns 0 if no memory
        // available, otherwise a properly aligned pointer to 'numBytes' of memory.
        //
        void *allocate(size_t numBytes);
    
        //
        // There is no deallocate.  The point of this class is that
        // deallocation can be skipped by the user of it, as the model
        // of use is to simultaneously deallocate everything at once
        // by calling pop(), and to not have to solve memory leak problems.
        //
    
        // Catch unwanted allocations.
        // TODO(jmadill): Remove this when we remove the global allocator.
        void lock();
        void unlock();
    
      private:
        size_t alignment;  // all returned allocations will be aligned at
                           // this granularity, which will be a power of 2
        size_t alignmentMask;
    
    #if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
        friend struct tHeader;
    
        struct tHeader
        {
            tHeader(tHeader *nextPage, size_t pageCount)
                : nextPage(nextPage),
                  pageCount(pageCount)
    #ifdef GUARD_BLOCKS
                  ,
                  lastAllocation(0)
    #endif
            {
            }
    
            ~tHeader()
            {
    #ifdef GUARD_BLOCKS
                if (lastAllocation)
                    lastAllocation->checkAllocList();
    #endif
            }
    
            tHeader *nextPage;
            size_t pageCount;
    #ifdef GUARD_BLOCKS
            TAllocation *lastAllocation;
    #endif
        };
    
        struct tAllocState
        {
            size_t offset;
            tHeader *page;
        };
        typedef std::vector<tAllocState> tAllocStack;
    
        // Track allocations if and only if we're using guard blocks
        void *initializeAllocation(tHeader *block, unsigned char *memory, size_t numBytes)
        {
    #ifdef GUARD_BLOCKS
            new (memory) TAllocation(numBytes, memory, block->lastAllocation);
            block->lastAllocation = reinterpret_cast<TAllocation *>(memory);
    #endif
            // This is optimized entirely away if GUARD_BLOCKS is not defined.
            return TAllocation::offsetAllocation(memory);
        }
    
        size_t pageSize;           // granularity of allocation from the OS
        size_t headerSkip;         // amount of memory to skip to make room for the
                                   //      header (basically, size of header, rounded
                                   //      up to make it aligned
        size_t currentPageOffset;  // next offset in top of inUseList to allocate from
        tHeader *freeList;         // list of popped memory
        tHeader *inUseList;        // list of all memory currently being used
        tAllocStack mStack;        // stack of where to allocate from, to partition pool
    
        int numCalls;       // just an interesting statistic
        size_t totalBytes;  // just an interesting statistic
    
    #else  // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC)
        std::vector<std::vector<void *>> mStack;
    #endif
    
        TPoolAllocator &operator=(const TPoolAllocator &);  // dont allow assignment operator
        TPoolAllocator(const TPoolAllocator &);             // dont allow default copy constructor
        bool mLocked;
    };
    
    //
    // There could potentially be many pools with pops happening at
    // different times.  But a simple use is to have a global pop
    // with everyone using the same global allocator.
    //
    extern TPoolAllocator *GetGlobalPoolAllocator();
    extern void SetGlobalPoolAllocator(TPoolAllocator *poolAllocator);
    
    //
    // This STL compatible allocator is intended to be used as the allocator
    // parameter to templatized STL containers, like vector and map.
    //
    // It will use the pools for allocation, and not
    // do any deallocation, but will still do destruction.
    //
    template <class T>
    class pool_allocator
    {
      public:
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;
        typedef T *pointer;
        typedef const T *const_pointer;
        typedef T &reference;
        typedef const T &const_reference;
        typedef T value_type;
    
        template <class Other>
        struct rebind
        {
            typedef pool_allocator<Other> other;
        };
        pointer address(reference x) const { return &x; }
        const_pointer address(const_reference x) const { return &x; }
    
        pool_allocator() {}
    
        template <class Other>
        pool_allocator(const pool_allocator<Other> &p)
        {
        }
    
        template <class Other>
        pool_allocator<T> &operator=(const pool_allocator<Other> &p)
        {
            return *this;
        }
    
    #if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
        // libCStd on some platforms have a different allocate/deallocate interface.
        // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be
        // allocated, not the number of elements.
        void *allocate(size_type n) { return getAllocator().allocate(n); }
        void *allocate(size_type n, const void *) { return getAllocator().allocate(n); }
        void deallocate(void *, size_type) {}
    #else
        pointer allocate(size_type n)
        {
            return static_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
        }
        pointer allocate(size_type n, const void *)
        {
            return static_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
        }
        void deallocate(pointer, size_type) {}
    #endif  // _RWSTD_ALLOCATOR
    
        void construct(pointer p, const T &val) { new ((void *)p) T(val); }
        void destroy(pointer p) { p->T::~T(); }
    
        bool operator==(const pool_allocator &rhs) const { return true; }
        bool operator!=(const pool_allocator &rhs) const { return false; }
    
        size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
        size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
    
        TPoolAllocator &getAllocator() const { return *GetGlobalPoolAllocator(); }
    };
    
    #endif  // COMPILER_TRANSLATOR_POOLALLOC_H_