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-06-02 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         4749033 :     BumpPointerPool* ensureCapacity(size_t size)
      56                 :     {
      57         4749033 :         void* allocationEnd = static_cast<char*>(m_current) + size;
      58         4749033 :         ASSERT(allocationEnd > m_current); // check for overflow
      59         4749033 :         if (allocationEnd <= static_cast<void*>(this))
      60         4718001 :             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         4749033 :     void* alloc(size_t size)
      67                 :     {
      68         4749033 :         void* current = m_current;
      69         4749033 :         void* allocationEnd = static_cast<char*>(current) + size;
      70         4749033 :         ASSERT(allocationEnd > current); // check for overflow
      71         4749033 :         ASSERT(allocationEnd <= static_cast<void*>(this));
      72         4749033 :         m_current = allocationEnd;
      73         4749033 :         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          134449 :     BumpPointerPool* dealloc(void* position)
      90                 :     {
      91          134449 :         if ((position >= m_start) && (position <= static_cast<void*>(this))) {
      92          134440 :             ASSERT(position <= m_current);
      93          134440 :             m_current = position;
      94          134440 :             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           31359 :     void* operator new(size_t size, const PageAllocation& allocation)
     102                 :     {
     103           31359 :         ASSERT(size < allocation.size());
     104           31359 :         return reinterpret_cast<char*>(reinterpret_cast<intptr_t>(allocation.base()) + allocation.size()) - size;
     105                 :     }
     106                 : 
     107           31359 :     BumpPointerPool(const PageAllocation& allocation)
     108           31359 :         : m_current(allocation.base())
     109           31359 :         , m_start(allocation.base())
     110                 :         , m_next(0)
     111                 :         , m_previous(0)
     112           62718 :         , m_allocation(allocation)
     113                 :     {
     114           31359 :     }
     115                 : 
     116           31359 :     static BumpPointerPool* create(size_t minimumCapacity = 0)
     117                 :     {
     118                 :         // Add size of BumpPointerPool object, check for overflow.
     119           31359 :         minimumCapacity += sizeof(BumpPointerPool);
     120           31359 :         if (minimumCapacity < sizeof(BumpPointerPool))
     121               0 :             return 0;
     122                 : 
     123           31359 :         size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
     124           62718 :         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           31359 :         PageAllocation allocation = PageAllocation::allocate(poolSize);
     133           31359 :         if (!!allocation)
     134           31359 :             return new(allocation) BumpPointerPool(allocation);
     135               0 :         return 0;
     136                 :     }
     137                 : 
     138           67716 :     void shrink()
     139                 :     {
     140           67716 :         ASSERT(!m_previous);
     141           67716 :         m_current = m_start;
     142          166464 :         while (m_next) {
     143           31032 :             BumpPointerPool* nextNext = m_next->m_next;
     144           31032 :             m_next->destroy();
     145           31032 :             m_next = nextNext;
     146                 :         }
     147           67716 :     }
     148                 : 
     149           31359 :     void destroy()
     150                 :     {
     151           31359 :         m_allocation.deallocate();
     152           31359 :     }
     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             345 :     BumpPointerAllocator()
     229             345 :         : m_head(0)
     230                 :     {
     231             345 :     }
     232                 : 
     233             345 :     ~BumpPointerAllocator()
     234                 :     {
     235             345 :         if (m_head)
     236             327 :             m_head->destroy();
     237             345 :     }
     238                 : 
     239           67716 :     BumpPointerPool* startAllocator()
     240                 :     {
     241           67716 :         if (!m_head)
     242             327 :             m_head = BumpPointerPool::create();
     243           67716 :         return m_head;
     244                 :     }
     245                 : 
     246           67716 :     void stopAllocator()
     247                 :     {
     248           67716 :         if (m_head)
     249           67716 :             m_head->shrink();
     250           67716 :     }
     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