js/src/gc/Nursery.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/gc/Nursery.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,332 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sw=4 et tw=78:
     1.6 + *
     1.7 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.9 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +#ifndef gc_Nursery_h
    1.12 +#define gc_Nursery_h
    1.13 +
    1.14 +#ifdef JSGC_GENERATIONAL
    1.15 +
    1.16 +#include "jsalloc.h"
    1.17 +#include "jspubtd.h"
    1.18 +
    1.19 +#include "ds/BitArray.h"
    1.20 +#include "gc/Heap.h"
    1.21 +#include "gc/Memory.h"
    1.22 +#include "js/GCAPI.h"
    1.23 +#include "js/HashTable.h"
    1.24 +#include "js/HeapAPI.h"
    1.25 +#include "js/Value.h"
    1.26 +#include "js/Vector.h"
    1.27 +
    1.28 +namespace JS {
    1.29 +struct Zone;
    1.30 +}
    1.31 +
    1.32 +namespace js {
    1.33 +
    1.34 +class ObjectElements;
    1.35 +class HeapSlot;
    1.36 +void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
    1.37 +
    1.38 +namespace gc {
    1.39 +class Cell;
    1.40 +class MinorCollectionTracer;
    1.41 +} /* namespace gc */
    1.42 +
    1.43 +namespace types {
    1.44 +struct TypeObject;
    1.45 +}
    1.46 +
    1.47 +namespace jit {
    1.48 +class CodeGenerator;
    1.49 +class MacroAssembler;
    1.50 +class ICStubCompiler;
    1.51 +class BaselineCompiler;
    1.52 +}
    1.53 +
    1.54 +class Nursery
    1.55 +{
    1.56 +  public:
    1.57 +    static const int NumNurseryChunks = 16;
    1.58 +    static const int LastNurseryChunk = NumNurseryChunks - 1;
    1.59 +    static const size_t Alignment = gc::ChunkSize;
    1.60 +    static const size_t ChunkShift = gc::ChunkShift;
    1.61 +    static const size_t NurserySize = gc::ChunkSize * NumNurseryChunks;
    1.62 +
    1.63 +    explicit Nursery(JSRuntime *rt)
    1.64 +      : runtime_(rt),
    1.65 +        position_(0),
    1.66 +        currentStart_(0),
    1.67 +        currentEnd_(0),
    1.68 +        currentChunk_(0),
    1.69 +        numActiveChunks_(0)
    1.70 +    {}
    1.71 +    ~Nursery();
    1.72 +
    1.73 +    bool init();
    1.74 +
    1.75 +    void enable();
    1.76 +    void disable();
    1.77 +    bool isEnabled() const { return numActiveChunks_ != 0; }
    1.78 +
    1.79 +    /* Return true if no allocations have been made since the last collection. */
    1.80 +    bool isEmpty() const;
    1.81 +
    1.82 +    template <typename T>
    1.83 +    MOZ_ALWAYS_INLINE bool isInside(const T *p) const {
    1.84 +        return gc::IsInsideNursery((JS::shadow::Runtime *)runtime_, p);
    1.85 +    }
    1.86 +
    1.87 +    /*
    1.88 +     * Allocate and return a pointer to a new GC object with its |slots|
    1.89 +     * pointer pre-filled. Returns nullptr if the Nursery is full.
    1.90 +     */
    1.91 +    JSObject *allocateObject(JSContext *cx, size_t size, size_t numDynamic);
    1.92 +
    1.93 +    /* Allocate a slots array for the given object. */
    1.94 +    HeapSlot *allocateSlots(JSContext *cx, JSObject *obj, uint32_t nslots);
    1.95 +
    1.96 +    /* Allocate an elements vector for the given object. */
    1.97 +    ObjectElements *allocateElements(JSContext *cx, JSObject *obj, uint32_t nelems);
    1.98 +
    1.99 +    /* Resize an existing slots array. */
   1.100 +    HeapSlot *reallocateSlots(JSContext *cx, JSObject *obj, HeapSlot *oldSlots,
   1.101 +                              uint32_t oldCount, uint32_t newCount);
   1.102 +
   1.103 +    /* Resize an existing elements vector. */
   1.104 +    ObjectElements *reallocateElements(JSContext *cx, JSObject *obj, ObjectElements *oldHeader,
   1.105 +                                       uint32_t oldCount, uint32_t newCount);
   1.106 +
   1.107 +    /* Free a slots array. */
   1.108 +    void freeSlots(JSContext *cx, HeapSlot *slots);
   1.109 +
   1.110 +    /* Add a slots to our tracking list if it is out-of-line. */
   1.111 +    void notifyInitialSlots(gc::Cell *cell, HeapSlot *slots);
   1.112 +
   1.113 +    typedef Vector<types::TypeObject *, 0, SystemAllocPolicy> TypeObjectList;
   1.114 +
   1.115 +    /*
   1.116 +     * Do a minor collection, optionally specifying a list to store types which
   1.117 +     * should be pretenured afterwards.
   1.118 +     */
   1.119 +    void collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList *pretenureTypes);
   1.120 +
   1.121 +    /*
   1.122 +     * Check if the thing at |*ref| in the Nursery has been forwarded. If so,
   1.123 +     * sets |*ref| to the new location of the object and returns true. Otherwise
   1.124 +     * returns false and leaves |*ref| unset.
   1.125 +     */
   1.126 +    template <typename T>
   1.127 +    MOZ_ALWAYS_INLINE bool getForwardedPointer(T **ref);
   1.128 +
   1.129 +    /* Forward a slots/elements pointer stored in an Ion frame. */
   1.130 +    void forwardBufferPointer(HeapSlot **pSlotsElems);
   1.131 +
   1.132 +    size_t sizeOfHeapCommitted() const {
   1.133 +        return numActiveChunks_ * gc::ChunkSize;
   1.134 +    }
   1.135 +    size_t sizeOfHeapDecommitted() const {
   1.136 +        return (NumNurseryChunks - numActiveChunks_) * gc::ChunkSize;
   1.137 +    }
   1.138 +    size_t sizeOfHugeSlots(mozilla::MallocSizeOf mallocSizeOf) const {
   1.139 +        size_t total = 0;
   1.140 +        for (HugeSlotsSet::Range r = hugeSlots.all(); !r.empty(); r.popFront())
   1.141 +            total += mallocSizeOf(r.front());
   1.142 +        total += hugeSlots.sizeOfExcludingThis(mallocSizeOf);
   1.143 +        return total;
   1.144 +    }
   1.145 +
   1.146 +    MOZ_ALWAYS_INLINE uintptr_t start() const {
   1.147 +        JS_ASSERT(runtime_);
   1.148 +        return ((JS::shadow::Runtime *)runtime_)->gcNurseryStart_;
   1.149 +    }
   1.150 +
   1.151 +    MOZ_ALWAYS_INLINE uintptr_t heapEnd() const {
   1.152 +        JS_ASSERT(runtime_);
   1.153 +        return ((JS::shadow::Runtime *)runtime_)->gcNurseryEnd_;
   1.154 +    }
   1.155 +
   1.156 +  private:
   1.157 +    /*
   1.158 +     * The start and end pointers are stored under the runtime so that we can
   1.159 +     * inline the isInsideNursery check into embedder code. Use the start()
   1.160 +     * and heapEnd() functions to access these values.
   1.161 +     */
   1.162 +    JSRuntime *runtime_;
   1.163 +
   1.164 +    /* Pointer to the first unallocated byte in the nursery. */
   1.165 +    uintptr_t position_;
   1.166 +
   1.167 +    /* Pointer to the logical start of the Nursery. */
   1.168 +    uintptr_t currentStart_;
   1.169 +
   1.170 +    /* Pointer to the last byte of space in the current chunk. */
   1.171 +    uintptr_t currentEnd_;
   1.172 +
   1.173 +    /* The index of the chunk that is currently being allocated from. */
   1.174 +    int currentChunk_;
   1.175 +
   1.176 +    /* The index after the last chunk that we will allocate from. */
   1.177 +    int numActiveChunks_;
   1.178 +
   1.179 +    /*
   1.180 +     * The set of externally malloced slots potentially kept live by objects
   1.181 +     * stored in the nursery. Any external slots that do not belong to a
   1.182 +     * tenured thing at the end of a minor GC must be freed.
   1.183 +     */
   1.184 +    typedef HashSet<HeapSlot *, PointerHasher<HeapSlot *, 3>, SystemAllocPolicy> HugeSlotsSet;
   1.185 +    HugeSlotsSet hugeSlots;
   1.186 +
   1.187 +    /* The maximum number of slots allowed to reside inline in the nursery. */
   1.188 +    static const size_t MaxNurserySlots = 128;
   1.189 +
   1.190 +    /* The amount of space in the mapped nursery available to allocations. */
   1.191 +    static const size_t NurseryChunkUsableSize = gc::ChunkSize - sizeof(gc::ChunkTrailer);
   1.192 +
   1.193 +    struct NurseryChunkLayout {
   1.194 +        char data[NurseryChunkUsableSize];
   1.195 +        gc::ChunkTrailer trailer;
   1.196 +        uintptr_t start() { return uintptr_t(&data); }
   1.197 +        uintptr_t end() { return uintptr_t(&trailer); }
   1.198 +    };
   1.199 +    static_assert(sizeof(NurseryChunkLayout) == gc::ChunkSize,
   1.200 +                  "Nursery chunk size must match gc::Chunk size.");
   1.201 +    NurseryChunkLayout &chunk(int index) const {
   1.202 +        JS_ASSERT(index < NumNurseryChunks);
   1.203 +        JS_ASSERT(start());
   1.204 +        return reinterpret_cast<NurseryChunkLayout *>(start())[index];
   1.205 +    }
   1.206 +
   1.207 +    MOZ_ALWAYS_INLINE void initChunk(int chunkno) {
   1.208 +        NurseryChunkLayout &c = chunk(chunkno);
   1.209 +        c.trailer.location = gc::ChunkLocationNursery;
   1.210 +        c.trailer.runtime = runtime();
   1.211 +    }
   1.212 +
   1.213 +    MOZ_ALWAYS_INLINE void setCurrentChunk(int chunkno) {
   1.214 +        JS_ASSERT(chunkno < NumNurseryChunks);
   1.215 +        JS_ASSERT(chunkno < numActiveChunks_);
   1.216 +        currentChunk_ = chunkno;
   1.217 +        position_ = chunk(chunkno).start();
   1.218 +        currentEnd_ = chunk(chunkno).end();
   1.219 +        initChunk(chunkno);
   1.220 +    }
   1.221 +
   1.222 +    void updateDecommittedRegion() {
   1.223 +#ifndef JS_GC_ZEAL
   1.224 +        if (numActiveChunks_ < NumNurseryChunks) {
   1.225 +            // Bug 994054: madvise on MacOS is too slow to make this
   1.226 +            //             optimization worthwhile.
   1.227 +# ifndef XP_MACOSX
   1.228 +            uintptr_t decommitStart = chunk(numActiveChunks_).start();
   1.229 +            JS_ASSERT(decommitStart == AlignBytes(decommitStart, 1 << 20));
   1.230 +            gc::MarkPagesUnused(runtime(), (void *)decommitStart, heapEnd() - decommitStart);
   1.231 +# endif
   1.232 +        }
   1.233 +#endif
   1.234 +    }
   1.235 +
   1.236 +    MOZ_ALWAYS_INLINE uintptr_t allocationEnd() const {
   1.237 +        JS_ASSERT(numActiveChunks_ > 0);
   1.238 +        return chunk(numActiveChunks_ - 1).end();
   1.239 +    }
   1.240 +
   1.241 +    MOZ_ALWAYS_INLINE bool isFullyGrown() const {
   1.242 +        return numActiveChunks_ == NumNurseryChunks;
   1.243 +    }
   1.244 +
   1.245 +    MOZ_ALWAYS_INLINE uintptr_t currentEnd() const {
   1.246 +        JS_ASSERT(runtime_);
   1.247 +        JS_ASSERT(currentEnd_ == chunk(currentChunk_).end());
   1.248 +        return currentEnd_;
   1.249 +    }
   1.250 +    void *addressOfCurrentEnd() const {
   1.251 +        JS_ASSERT(runtime_);
   1.252 +        return (void *)&currentEnd_;
   1.253 +    }
   1.254 +
   1.255 +    uintptr_t position() const { return position_; }
   1.256 +    void *addressOfPosition() const { return (void*)&position_; }
   1.257 +
   1.258 +    JSRuntime *runtime() const { return runtime_; }
   1.259 +
   1.260 +    /* Allocates and registers external slots with the nursery. */
   1.261 +    HeapSlot *allocateHugeSlots(JSContext *cx, size_t nslots);
   1.262 +
   1.263 +    /* Allocates a new GC thing from the tenured generation during minor GC. */
   1.264 +    void *allocateFromTenured(JS::Zone *zone, gc::AllocKind thingKind);
   1.265 +
   1.266 +    struct TenureCountCache;
   1.267 +
   1.268 +    /* Common internal allocator function. */
   1.269 +    void *allocate(size_t size);
   1.270 +
   1.271 +    /*
   1.272 +     * Move the object at |src| in the Nursery to an already-allocated cell
   1.273 +     * |dst| in Tenured.
   1.274 +     */
   1.275 +    void collectToFixedPoint(gc::MinorCollectionTracer *trc, TenureCountCache &tenureCounts);
   1.276 +    MOZ_ALWAYS_INLINE void traceObject(gc::MinorCollectionTracer *trc, JSObject *src);
   1.277 +    MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer *trc, HeapSlot *vp, uint32_t nslots);
   1.278 +    MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer *trc, HeapSlot *vp, HeapSlot *end);
   1.279 +    MOZ_ALWAYS_INLINE void markSlot(gc::MinorCollectionTracer *trc, HeapSlot *slotp);
   1.280 +    void *moveToTenured(gc::MinorCollectionTracer *trc, JSObject *src);
   1.281 +    size_t moveObjectToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
   1.282 +    size_t moveElementsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
   1.283 +    size_t moveSlotsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
   1.284 +    void forwardTypedArrayPointers(JSObject *dst, JSObject *src);
   1.285 +
   1.286 +    /* Handle relocation of slots/elements pointers stored in Ion frames. */
   1.287 +    void setSlotsForwardingPointer(HeapSlot *oldSlots, HeapSlot *newSlots, uint32_t nslots);
   1.288 +    void setElementsForwardingPointer(ObjectElements *oldHeader, ObjectElements *newHeader,
   1.289 +                                      uint32_t nelems);
   1.290 +
   1.291 +    /* Free malloced pointers owned by freed things in the nursery. */
   1.292 +    void freeHugeSlots(JSRuntime *rt);
   1.293 +
   1.294 +    /*
   1.295 +     * Frees all non-live nursery-allocated things at the end of a minor
   1.296 +     * collection.
   1.297 +     */
   1.298 +    void sweep(JSRuntime *rt);
   1.299 +
   1.300 +    /* Change the allocable space provided by the nursery. */
   1.301 +    void growAllocableSpace();
   1.302 +    void shrinkAllocableSpace();
   1.303 +
   1.304 +    static void MinorGCCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind);
   1.305 +
   1.306 +#ifdef JS_GC_ZEAL
   1.307 +    /*
   1.308 +     * In debug and zeal builds, these bytes indicate the state of an unused
   1.309 +     * segment of nursery-allocated memory.
   1.310 +     */
   1.311 +    void enterZealMode() {
   1.312 +        if (isEnabled())
   1.313 +            numActiveChunks_ = NumNurseryChunks;
   1.314 +    }
   1.315 +    void leaveZealMode() {
   1.316 +        if (isEnabled()) {
   1.317 +            JS_ASSERT(isEmpty());
   1.318 +            setCurrentChunk(0);
   1.319 +            currentStart_ = start();
   1.320 +        }
   1.321 +    }
   1.322 +#else
   1.323 +    void enterZealMode() {}
   1.324 +    void leaveZealMode() {}
   1.325 +#endif
   1.326 +
   1.327 +    friend class gc::MinorCollectionTracer;
   1.328 +    friend class jit::MacroAssembler;
   1.329 +    friend void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
   1.330 +};
   1.331 +
   1.332 +} /* namespace js */
   1.333 +
   1.334 +#endif /* JSGC_GENERATIONAL */
   1.335 +#endif /* gc_Nursery_h */

mercurial