js/src/ds/LifoAlloc.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "ds/LifoAlloc.h"
     9 #include "mozilla/MathAlgorithms.h"
    11 using namespace js;
    13 using mozilla::RoundUpPow2;
    14 using mozilla::tl::BitSize;
    16 namespace js {
    17 namespace detail {
    19 BumpChunk *
    20 BumpChunk::new_(size_t chunkSize)
    21 {
    22     JS_ASSERT(RoundUpPow2(chunkSize) == chunkSize);
    23     void *mem = js_malloc(chunkSize);
    24     if (!mem)
    25         return nullptr;
    26     BumpChunk *result = new (mem) BumpChunk(chunkSize - sizeof(BumpChunk));
    28     // We assume that the alignment of sAlign is less than that of
    29     // the underlying memory allocator -- creating a new BumpChunk should
    30     // always satisfy the sAlign alignment constraint.
    31     JS_ASSERT(AlignPtr(result->bump) == result->bump);
    32     return result;
    33 }
    35 void
    36 BumpChunk::delete_(BumpChunk *chunk)
    37 {
    38 #ifdef DEBUG
    39     // Part of the chunk may have been marked as poisoned/noaccess.  Undo that
    40     // before writing the 0xcd bytes.
    41     size_t size = sizeof(*chunk) + chunk->bumpSpaceSize;
    42     MOZ_MAKE_MEM_UNDEFINED(chunk, size);
    43     memset(chunk, 0xcd, size);
    44 #endif
    45     js_free(chunk);
    46 }
    48 bool
    49 BumpChunk::canAlloc(size_t n)
    50 {
    51     char *aligned = AlignPtr(bump);
    52     char *bumped = aligned + n;
    53     return bumped <= limit && bumped > headerBase();
    54 }
    56 } // namespace detail
    57 } // namespace js
    59 void
    60 LifoAlloc::freeAll()
    61 {
    62     while (first) {
    63         BumpChunk *victim = first;
    64         first = first->next();
    65         decrementCurSize(victim->computedSizeOfIncludingThis());
    66         BumpChunk::delete_(victim);
    67     }
    68     first = latest = last = nullptr;
    70     // Nb: maintaining curSize_ correctly isn't easy.  Fortunately, this is an
    71     // excellent sanity check.
    72     JS_ASSERT(curSize_ == 0);
    73 }
    75 LifoAlloc::BumpChunk *
    76 LifoAlloc::getOrCreateChunk(size_t n)
    77 {
    78     if (first) {
    79         // Look for existing, unused BumpChunks to satisfy the request.
    80         while (latest->next()) {
    81             latest = latest->next();
    82             latest->resetBump();    // This was an unused BumpChunk on the chain.
    83             if (latest->canAlloc(n))
    84                 return latest;
    85         }
    86     }
    88     size_t defaultChunkFreeSpace = defaultChunkSize_ - sizeof(BumpChunk);
    89     size_t chunkSize;
    90     if (n > defaultChunkFreeSpace) {
    91         size_t allocSizeWithHeader = n + sizeof(BumpChunk);
    93         // Guard for overflow.
    94         if (allocSizeWithHeader < n ||
    95             (allocSizeWithHeader & (size_t(1) << (BitSize<size_t>::value - 1)))) {
    96             return nullptr;
    97         }
    99         chunkSize = RoundUpPow2(allocSizeWithHeader);
   100     } else {
   101         chunkSize = defaultChunkSize_;
   102     }
   104     // If we get here, we couldn't find an existing BumpChunk to fill the request.
   105     BumpChunk *newChunk = BumpChunk::new_(chunkSize);
   106     if (!newChunk)
   107         return nullptr;
   108     if (!first) {
   109         latest = first = last = newChunk;
   110     } else {
   111         JS_ASSERT(latest && !latest->next());
   112         latest->setNext(newChunk);
   113         latest = last = newChunk;
   114     }
   116     size_t computedChunkSize = newChunk->computedSizeOfIncludingThis();
   117     JS_ASSERT(computedChunkSize == chunkSize);
   118     incrementCurSize(computedChunkSize);
   120     return newChunk;
   121 }
   123 void
   124 LifoAlloc::transferFrom(LifoAlloc *other)
   125 {
   126     JS_ASSERT(!markCount);
   127     JS_ASSERT(!other->markCount);
   129     if (!other->first)
   130         return;
   132     incrementCurSize(other->curSize_);
   133     if (other->isEmpty())
   134         appendUnused(other->first, other->last);
   135     else
   136         appendUsed(other->first, other->latest, other->last);
   137     other->first = other->last = other->latest = nullptr;
   138     other->curSize_ = 0;
   139 }
   141 void
   142 LifoAlloc::transferUnusedFrom(LifoAlloc *other)
   143 {
   144     JS_ASSERT(!markCount);
   145     JS_ASSERT(latest == first);
   147     if (other->markCount || !other->first)
   148         return;
   150     // Transfer all chunks *after* |latest|.
   152     if (other->latest->next()) {
   153         if (other->latest == other->first) {
   154             // We're transferring everything except the first chunk.
   155             size_t delta = other->curSize_ - other->first->computedSizeOfIncludingThis();
   156             other->decrementCurSize(delta);
   157             incrementCurSize(delta);
   158         } else {
   159             for (BumpChunk *chunk = other->latest->next(); chunk; chunk = chunk->next()) {
   160                 size_t size = chunk->computedSizeOfIncludingThis();
   161                 incrementCurSize(size);
   162                 other->decrementCurSize(size);
   163             }
   164         }
   166         appendUnused(other->latest->next(), other->last);
   167         other->latest->setNext(nullptr);
   168         other->last = other->latest;
   169     }
   170 }

mercurial