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