LCOV - app.info - js/src/yarr/BumpPointerAllocator.h

LCOV - code coverage report
| Current view: | directory - js/src/yarr - BumpPointerAllocator.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 93 | 81 | 87.1 %
| Date: | 2012-04-07 | Functions: | 14 | 14 | 100.0 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Copyright (C) 2010 Apple Inc. All rights reserved.
           6                 :  *
           7                 :  * Redistribution and use in source and binary forms, with or without
           8                 :  * modification, are permitted provided that the following conditions
           9                 :  * are met:
          10                 :  * 1. Redistributions of source code must retain the above copyright
          11                 :  *    notice, this list of conditions and the following disclaimer.
          12                 :  * 2. Redistributions in binary form must reproduce the above copyright
          13                 :  *    notice, this list of conditions and the following disclaimer in the
          14                 :  *    documentation and/or other materials provided with the distribution.
          15                 :  *
          16                 :  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
          17                 :  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
          18                 :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
          19                 :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
          20                 :  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
          21                 :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
          22                 :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
          23                 :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
          24                 :  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
          25                 :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
          26                 :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
          27                 :  *
          28                 :  * ***** END LICENSE BLOCK ***** */
          29                 :
          30                 : #ifndef BumpPointerAllocator_h
          31                 : #define BumpPointerAllocator_h
          32                 :
          33                 : #include "PageAllocation.h"
          34                 :
          35                 : namespace WTF {
          36                 :
          37                 : #if WTF_CPU_SPARC
          38                 : #define MINIMUM_BUMP_POOL_SIZE 0x2000
          39                 : #elif WTF_CPU_IA64
          40                 : #define MINIMUM_BUMP_POOL_SIZE 0x4000
          41                 : #else
          42                 : #define MINIMUM_BUMP_POOL_SIZE 0x1000
          43                 : #endif
          44                 :
          45                 : class BumpPointerPool {
          46                 : public:
          47                 :     // ensureCapacity will check whether the current pool has capacity to
          48                 :     // allocate 'size' bytes of memory  If it does not, it will attempt to
          49                 :     // allocate a new pool (which will be added to this one in a chain).
          50                 :     //
          51                 :     // If allocation fails (out of memory) this method will return null.
          52                 :     // If the return value is non-null, then callers should update any
          53                 :     // references they have to this current (possibly full) BumpPointerPool
          54                 :     // to instead point to the newly returned BumpPointerPool.
          55         4724253 :     BumpPointerPool* ensureCapacity(size_t size)
          56                 :     {
          57         4724253 :         void* allocationEnd = static_cast<char*>(m_current) + size;
          58         4724253 :         ASSERT(allocationEnd > m_current); // check for overflow
          59         4724253 :         if (allocationEnd <= static_cast<void*>(this))
          60         4693221 :             return this;
          61           31032 :         return ensureCapacityCrossPool(this, size);
          62                 :     }
          63                 :
          64                 :     // alloc should only be called after calling ensureCapacity; as such
          65                 :     // alloc will never fail.
          66         4724253 :     void* alloc(size_t size)
          67                 :     {
          68         4724253 :         void* current = m_current;
          69         4724253 :         void* allocationEnd = static_cast<char*>(current) + size;
          70         4724253 :         ASSERT(allocationEnd > current); // check for overflow
          71         4724253 :         ASSERT(allocationEnd <= static_cast<void*>(this));
          72         4724253 :         m_current = allocationEnd;
          73         4724253 :         return current;
          74                 :     }
          75                 :
          76                 :     // The dealloc method releases memory allocated using alloc.  Memory
          77                 :     // must be released in a LIFO fashion, e.g. if the client calls alloc
          78                 :     // four times, returning pointer A, B, C, D, then the only valid order
          79                 :     // in which these may be deallocaed is D, C, B, A.
          80                 :     //
          81                 :     // The client may optionally skip some deallocations.  In the example
          82                 :     // above, it would be valid to only explicitly dealloc C, A (D being
          83                 :     // dealloced along with C, B along with A).
          84                 :     //
          85                 :     // If pointer was not allocated from this pool (or pools) then dealloc
          86                 :     // will CRASH().  Callers should update any references they have to
          87                 :     // this current BumpPointerPool to instead point to the returned
          88                 :     // BumpPointerPool.
          89          110196 :     BumpPointerPool* dealloc(void* position)
          90                 :     {
          91          110196 :         if ((position >= m_start) && (position <= static_cast<void*>(this))) {
          92          110187 :             ASSERT(position <= m_current);
          93          110187 :             m_current = position;
          94          110187 :             return this;
          95                 :         }
          96               9 :         return deallocCrossPool(this, position);
          97                 :     }
          98                 :
          99                 : private:
         100                 :     // Placement operator new, returns the last 'size' bytes of allocation for use as this.
         101           31104 :     void* operator new(size_t size, const PageAllocation& allocation)
         102                 :     {
         103           31104 :         ASSERT(size < allocation.size());
         104           31104 :         return reinterpret_cast<char*>(reinterpret_cast<intptr_t>(allocation.base()) + allocation.size()) - size;
         105                 :     }
         106                 :
         107           31104 :     BumpPointerPool(const PageAllocation& allocation)
         108           31104 :         : m_current(allocation.base())
         109           31104 :         , m_start(allocation.base())
         110                 :         , m_next(0)
         111                 :         , m_previous(0)
         112           62208 :         , m_allocation(allocation)
         113                 :     {
         114           31104 :     }
         115                 :
         116           31104 :     static BumpPointerPool* create(size_t minimumCapacity = 0)
         117                 :     {
         118                 :         // Add size of BumpPointerPool object, check for overflow.
         119           31104 :         minimumCapacity += sizeof(BumpPointerPool);
         120           31104 :         if (minimumCapacity < sizeof(BumpPointerPool))
         121               0 :             return 0;
         122                 :
         123           31104 :         size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
         124           62208 :         while (poolSize < minimumCapacity) {
         125               0 :             poolSize <<= 1;
         126                 :             // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
         127                 :             ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
         128               0 :             if (!poolSize)
         129               0 :                 return 0;
         130                 :         }
         131                 :
         132           31104 :         PageAllocation allocation = PageAllocation::allocate(poolSize);
         133           31104 :         if (!!allocation)
         134           31104 :             return new(allocation) BumpPointerPool(allocation);
         135               0 :         return 0;
         136                 :     }
         137                 :
         138           57033 :     void shrink()
         139                 :     {
         140           57033 :         ASSERT(!m_previous);
         141           57033 :         m_current = m_start;
         142          145098 :         while (m_next) {
         143           31032 :             BumpPointerPool* nextNext = m_next->m_next;
         144           31032 :             m_next->destroy();
         145           31032 :             m_next = nextNext;
         146                 :         }
         147           57033 :     }
         148                 :
         149           31104 :     void destroy()
         150                 :     {
         151           31104 :         m_allocation.deallocate();
         152           31104 :     }
         153                 :
         154           31032 :     static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
         155                 :     {
         156                 :         // The pool passed should not have capacity, so we'll start with the next one.
         157           31032 :         ASSERT(previousPool);
         158           31032 :         ASSERT((static_cast<char*>(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
         159           31032 :         ASSERT((static_cast<char*>(previousPool->m_current) + size) > static_cast<void*>(previousPool));
         160           31032 :         BumpPointerPool* pool = previousPool->m_next;
         161                 :
         162               0 :         while (true) {
         163           31032 :             if (!pool) {
         164                 :                 // We've run to the end; allocate a new pool.
         165           31032 :                 pool = BumpPointerPool::create(size);
         166           31032 :                 previousPool->m_next = pool;
         167           31032 :                 pool->m_previous = previousPool;
         168           31032 :                 return pool;
         169                 :             }
         170                 :
         171                 :             //
         172               0 :             void* current = pool->m_current;
         173               0 :             void* allocationEnd = static_cast<char*>(current) + size;
         174               0 :             ASSERT(allocationEnd > current); // check for overflow
         175               0 :             if (allocationEnd <= static_cast<void*>(pool))
         176               0 :                 return pool;
         177                 :         }
         178                 :     }
         179                 :
         180               9 :     static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
         181                 :     {
         182                 :         // Should only be called if position is not in the current pool.
         183               9 :         ASSERT((position < pool->m_start) || (position > static_cast<void*>(pool)));
         184                 :
         185           31023 :         while (true) {
         186                 :             // Unwind the current pool to the start, move back in the chain to the previous pool.
         187           31032 :             pool->m_current = pool->m_start;
         188           31032 :             pool = pool->m_previous;
         189                 :
         190                 :             // position was nowhere in the chain!
         191           31032 :             if (!pool)
         192               0 :                 CRASH();
         193                 :
         194           31032 :             if ((position >= pool->m_start) && (position <= static_cast<void*>(pool))) {
         195               9 :                 ASSERT(position <= pool->m_current);
         196               9 :                 pool->m_current = position;
         197               9 :                 return pool;
         198                 :             }
         199                 :         }
         200                 :     }
         201                 :
         202                 :     void* m_current;
         203                 :     void* m_start;
         204                 :     BumpPointerPool* m_next;
         205                 :     BumpPointerPool* m_previous;
         206                 :     PageAllocation m_allocation;
         207                 :
         208                 :     friend class BumpPointerAllocator;
         209                 : };
         210                 :
         211                 : // A BumpPointerAllocator manages a set of BumpPointerPool objects, which
         212                 : // can be used for LIFO (stack like) allocation.
         213                 : //
         214                 : // To begin allocating using this class call startAllocator().  The result
         215                 : // of this method will be null if the initial pool allocation fails, or a
         216                 : // pointer to a BumpPointerPool object that can be used to perform
         217                 : // allocations.  Whilst running no memory will be released until
         218                 : // stopAllocator() is called.  At this point all allocations made through
         219                 : // this allocator will be reaped, and underlying memory may be freed.
         220                 : //
         221                 : // (In practice we will still hold on to the initial pool to allow allocation
         222                 : // to be quickly restared, but aditional pools will be freed).
         223                 : //
         224                 : // This allocator is non-renetrant, it is encumbant on the clients to ensure
         225                 : // startAllocator() is not called again until stopAllocator() has been called.
         226                 : class BumpPointerAllocator {
         227                 : public:
         228              90 :     BumpPointerAllocator()
         229              90 :         : m_head(0)
         230                 :     {
         231              90 :     }
         232                 :
         233              90 :     ~BumpPointerAllocator()
         234                 :     {
         235              90 :         if (m_head)
         236              72 :             m_head->destroy();
         237              90 :     }
         238                 :
         239           57033 :     BumpPointerPool* startAllocator()
         240                 :     {
         241           57033 :         if (!m_head)
         242              72 :             m_head = BumpPointerPool::create();
         243           57033 :         return m_head;
         244                 :     }
         245                 :
         246           57033 :     void stopAllocator()
         247                 :     {
         248           57033 :         if (m_head)
         249           57033 :             m_head->shrink();
         250           57033 :     }
         251                 :
         252                 : private:
         253                 :     BumpPointerPool* m_head;
         254                 : };
         255                 :
         256                 : }
         257                 :
         258                 : using WTF::BumpPointerAllocator;
         259                 :
         260                 : #endif // BumpPointerAllocator_h

Generated by: LCOV version 1.7