js/src/ds/LifoAlloc.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/ds/LifoAlloc.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,170 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "ds/LifoAlloc.h"
    1.11 +
    1.12 +#include "mozilla/MathAlgorithms.h"
    1.13 +
    1.14 +using namespace js;
    1.15 +
    1.16 +using mozilla::RoundUpPow2;
    1.17 +using mozilla::tl::BitSize;
    1.18 +
    1.19 +namespace js {
    1.20 +namespace detail {
    1.21 +
    1.22 +BumpChunk *
    1.23 +BumpChunk::new_(size_t chunkSize)
    1.24 +{
    1.25 +    JS_ASSERT(RoundUpPow2(chunkSize) == chunkSize);
    1.26 +    void *mem = js_malloc(chunkSize);
    1.27 +    if (!mem)
    1.28 +        return nullptr;
    1.29 +    BumpChunk *result = new (mem) BumpChunk(chunkSize - sizeof(BumpChunk));
    1.30 +
    1.31 +    // We assume that the alignment of sAlign is less than that of
    1.32 +    // the underlying memory allocator -- creating a new BumpChunk should
    1.33 +    // always satisfy the sAlign alignment constraint.
    1.34 +    JS_ASSERT(AlignPtr(result->bump) == result->bump);
    1.35 +    return result;
    1.36 +}
    1.37 +
    1.38 +void
    1.39 +BumpChunk::delete_(BumpChunk *chunk)
    1.40 +{
    1.41 +#ifdef DEBUG
    1.42 +    // Part of the chunk may have been marked as poisoned/noaccess.  Undo that
    1.43 +    // before writing the 0xcd bytes.
    1.44 +    size_t size = sizeof(*chunk) + chunk->bumpSpaceSize;
    1.45 +    MOZ_MAKE_MEM_UNDEFINED(chunk, size);
    1.46 +    memset(chunk, 0xcd, size);
    1.47 +#endif
    1.48 +    js_free(chunk);
    1.49 +}
    1.50 +
    1.51 +bool
    1.52 +BumpChunk::canAlloc(size_t n)
    1.53 +{
    1.54 +    char *aligned = AlignPtr(bump);
    1.55 +    char *bumped = aligned + n;
    1.56 +    return bumped <= limit && bumped > headerBase();
    1.57 +}
    1.58 +
    1.59 +} // namespace detail
    1.60 +} // namespace js
    1.61 +
    1.62 +void
    1.63 +LifoAlloc::freeAll()
    1.64 +{
    1.65 +    while (first) {
    1.66 +        BumpChunk *victim = first;
    1.67 +        first = first->next();
    1.68 +        decrementCurSize(victim->computedSizeOfIncludingThis());
    1.69 +        BumpChunk::delete_(victim);
    1.70 +    }
    1.71 +    first = latest = last = nullptr;
    1.72 +
    1.73 +    // Nb: maintaining curSize_ correctly isn't easy.  Fortunately, this is an
    1.74 +    // excellent sanity check.
    1.75 +    JS_ASSERT(curSize_ == 0);
    1.76 +}
    1.77 +
    1.78 +LifoAlloc::BumpChunk *
    1.79 +LifoAlloc::getOrCreateChunk(size_t n)
    1.80 +{
    1.81 +    if (first) {
    1.82 +        // Look for existing, unused BumpChunks to satisfy the request.
    1.83 +        while (latest->next()) {
    1.84 +            latest = latest->next();
    1.85 +            latest->resetBump();    // This was an unused BumpChunk on the chain.
    1.86 +            if (latest->canAlloc(n))
    1.87 +                return latest;
    1.88 +        }
    1.89 +    }
    1.90 +
    1.91 +    size_t defaultChunkFreeSpace = defaultChunkSize_ - sizeof(BumpChunk);
    1.92 +    size_t chunkSize;
    1.93 +    if (n > defaultChunkFreeSpace) {
    1.94 +        size_t allocSizeWithHeader = n + sizeof(BumpChunk);
    1.95 +
    1.96 +        // Guard for overflow.
    1.97 +        if (allocSizeWithHeader < n ||
    1.98 +            (allocSizeWithHeader & (size_t(1) << (BitSize<size_t>::value - 1)))) {
    1.99 +            return nullptr;
   1.100 +        }
   1.101 +
   1.102 +        chunkSize = RoundUpPow2(allocSizeWithHeader);
   1.103 +    } else {
   1.104 +        chunkSize = defaultChunkSize_;
   1.105 +    }
   1.106 +
   1.107 +    // If we get here, we couldn't find an existing BumpChunk to fill the request.
   1.108 +    BumpChunk *newChunk = BumpChunk::new_(chunkSize);
   1.109 +    if (!newChunk)
   1.110 +        return nullptr;
   1.111 +    if (!first) {
   1.112 +        latest = first = last = newChunk;
   1.113 +    } else {
   1.114 +        JS_ASSERT(latest && !latest->next());
   1.115 +        latest->setNext(newChunk);
   1.116 +        latest = last = newChunk;
   1.117 +    }
   1.118 +
   1.119 +    size_t computedChunkSize = newChunk->computedSizeOfIncludingThis();
   1.120 +    JS_ASSERT(computedChunkSize == chunkSize);
   1.121 +    incrementCurSize(computedChunkSize);
   1.122 +
   1.123 +    return newChunk;
   1.124 +}
   1.125 +
   1.126 +void
   1.127 +LifoAlloc::transferFrom(LifoAlloc *other)
   1.128 +{
   1.129 +    JS_ASSERT(!markCount);
   1.130 +    JS_ASSERT(!other->markCount);
   1.131 +
   1.132 +    if (!other->first)
   1.133 +        return;
   1.134 +
   1.135 +    incrementCurSize(other->curSize_);
   1.136 +    if (other->isEmpty())
   1.137 +        appendUnused(other->first, other->last);
   1.138 +    else
   1.139 +        appendUsed(other->first, other->latest, other->last);
   1.140 +    other->first = other->last = other->latest = nullptr;
   1.141 +    other->curSize_ = 0;
   1.142 +}
   1.143 +
   1.144 +void
   1.145 +LifoAlloc::transferUnusedFrom(LifoAlloc *other)
   1.146 +{
   1.147 +    JS_ASSERT(!markCount);
   1.148 +    JS_ASSERT(latest == first);
   1.149 +
   1.150 +    if (other->markCount || !other->first)
   1.151 +        return;
   1.152 +
   1.153 +    // Transfer all chunks *after* |latest|.
   1.154 +
   1.155 +    if (other->latest->next()) {
   1.156 +        if (other->latest == other->first) {
   1.157 +            // We're transferring everything except the first chunk.
   1.158 +            size_t delta = other->curSize_ - other->first->computedSizeOfIncludingThis();
   1.159 +            other->decrementCurSize(delta);
   1.160 +            incrementCurSize(delta);
   1.161 +        } else {
   1.162 +            for (BumpChunk *chunk = other->latest->next(); chunk; chunk = chunk->next()) {
   1.163 +                size_t size = chunk->computedSizeOfIncludingThis();
   1.164 +                incrementCurSize(size);
   1.165 +                other->decrementCurSize(size);
   1.166 +            }
   1.167 +        }
   1.168 +
   1.169 +        appendUnused(other->latest->next(), other->last);
   1.170 +        other->latest->setNext(nullptr);
   1.171 +        other->last = other->latest;
   1.172 +    }
   1.173 +}

mercurial