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 *)¤tEnd_; 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 */