js/src/gc/Nursery.h

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.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sw=4 et tw=78:
michael@0 3 *
michael@0 4 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 6 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #ifndef gc_Nursery_h
michael@0 9 #define gc_Nursery_h
michael@0 10
michael@0 11 #ifdef JSGC_GENERATIONAL
michael@0 12
michael@0 13 #include "jsalloc.h"
michael@0 14 #include "jspubtd.h"
michael@0 15
michael@0 16 #include "ds/BitArray.h"
michael@0 17 #include "gc/Heap.h"
michael@0 18 #include "gc/Memory.h"
michael@0 19 #include "js/GCAPI.h"
michael@0 20 #include "js/HashTable.h"
michael@0 21 #include "js/HeapAPI.h"
michael@0 22 #include "js/Value.h"
michael@0 23 #include "js/Vector.h"
michael@0 24
michael@0 25 namespace JS {
michael@0 26 struct Zone;
michael@0 27 }
michael@0 28
michael@0 29 namespace js {
michael@0 30
michael@0 31 class ObjectElements;
michael@0 32 class HeapSlot;
michael@0 33 void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
michael@0 34
michael@0 35 namespace gc {
michael@0 36 class Cell;
michael@0 37 class MinorCollectionTracer;
michael@0 38 } /* namespace gc */
michael@0 39
michael@0 40 namespace types {
michael@0 41 struct TypeObject;
michael@0 42 }
michael@0 43
michael@0 44 namespace jit {
michael@0 45 class CodeGenerator;
michael@0 46 class MacroAssembler;
michael@0 47 class ICStubCompiler;
michael@0 48 class BaselineCompiler;
michael@0 49 }
michael@0 50
michael@0 51 class Nursery
michael@0 52 {
michael@0 53 public:
michael@0 54 static const int NumNurseryChunks = 16;
michael@0 55 static const int LastNurseryChunk = NumNurseryChunks - 1;
michael@0 56 static const size_t Alignment = gc::ChunkSize;
michael@0 57 static const size_t ChunkShift = gc::ChunkShift;
michael@0 58 static const size_t NurserySize = gc::ChunkSize * NumNurseryChunks;
michael@0 59
michael@0 60 explicit Nursery(JSRuntime *rt)
michael@0 61 : runtime_(rt),
michael@0 62 position_(0),
michael@0 63 currentStart_(0),
michael@0 64 currentEnd_(0),
michael@0 65 currentChunk_(0),
michael@0 66 numActiveChunks_(0)
michael@0 67 {}
michael@0 68 ~Nursery();
michael@0 69
michael@0 70 bool init();
michael@0 71
michael@0 72 void enable();
michael@0 73 void disable();
michael@0 74 bool isEnabled() const { return numActiveChunks_ != 0; }
michael@0 75
michael@0 76 /* Return true if no allocations have been made since the last collection. */
michael@0 77 bool isEmpty() const;
michael@0 78
michael@0 79 template <typename T>
michael@0 80 MOZ_ALWAYS_INLINE bool isInside(const T *p) const {
michael@0 81 return gc::IsInsideNursery((JS::shadow::Runtime *)runtime_, p);
michael@0 82 }
michael@0 83
michael@0 84 /*
michael@0 85 * Allocate and return a pointer to a new GC object with its |slots|
michael@0 86 * pointer pre-filled. Returns nullptr if the Nursery is full.
michael@0 87 */
michael@0 88 JSObject *allocateObject(JSContext *cx, size_t size, size_t numDynamic);
michael@0 89
michael@0 90 /* Allocate a slots array for the given object. */
michael@0 91 HeapSlot *allocateSlots(JSContext *cx, JSObject *obj, uint32_t nslots);
michael@0 92
michael@0 93 /* Allocate an elements vector for the given object. */
michael@0 94 ObjectElements *allocateElements(JSContext *cx, JSObject *obj, uint32_t nelems);
michael@0 95
michael@0 96 /* Resize an existing slots array. */
michael@0 97 HeapSlot *reallocateSlots(JSContext *cx, JSObject *obj, HeapSlot *oldSlots,
michael@0 98 uint32_t oldCount, uint32_t newCount);
michael@0 99
michael@0 100 /* Resize an existing elements vector. */
michael@0 101 ObjectElements *reallocateElements(JSContext *cx, JSObject *obj, ObjectElements *oldHeader,
michael@0 102 uint32_t oldCount, uint32_t newCount);
michael@0 103
michael@0 104 /* Free a slots array. */
michael@0 105 void freeSlots(JSContext *cx, HeapSlot *slots);
michael@0 106
michael@0 107 /* Add a slots to our tracking list if it is out-of-line. */
michael@0 108 void notifyInitialSlots(gc::Cell *cell, HeapSlot *slots);
michael@0 109
michael@0 110 typedef Vector<types::TypeObject *, 0, SystemAllocPolicy> TypeObjectList;
michael@0 111
michael@0 112 /*
michael@0 113 * Do a minor collection, optionally specifying a list to store types which
michael@0 114 * should be pretenured afterwards.
michael@0 115 */
michael@0 116 void collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList *pretenureTypes);
michael@0 117
michael@0 118 /*
michael@0 119 * Check if the thing at |*ref| in the Nursery has been forwarded. If so,
michael@0 120 * sets |*ref| to the new location of the object and returns true. Otherwise
michael@0 121 * returns false and leaves |*ref| unset.
michael@0 122 */
michael@0 123 template <typename T>
michael@0 124 MOZ_ALWAYS_INLINE bool getForwardedPointer(T **ref);
michael@0 125
michael@0 126 /* Forward a slots/elements pointer stored in an Ion frame. */
michael@0 127 void forwardBufferPointer(HeapSlot **pSlotsElems);
michael@0 128
michael@0 129 size_t sizeOfHeapCommitted() const {
michael@0 130 return numActiveChunks_ * gc::ChunkSize;
michael@0 131 }
michael@0 132 size_t sizeOfHeapDecommitted() const {
michael@0 133 return (NumNurseryChunks - numActiveChunks_) * gc::ChunkSize;
michael@0 134 }
michael@0 135 size_t sizeOfHugeSlots(mozilla::MallocSizeOf mallocSizeOf) const {
michael@0 136 size_t total = 0;
michael@0 137 for (HugeSlotsSet::Range r = hugeSlots.all(); !r.empty(); r.popFront())
michael@0 138 total += mallocSizeOf(r.front());
michael@0 139 total += hugeSlots.sizeOfExcludingThis(mallocSizeOf);
michael@0 140 return total;
michael@0 141 }
michael@0 142
michael@0 143 MOZ_ALWAYS_INLINE uintptr_t start() const {
michael@0 144 JS_ASSERT(runtime_);
michael@0 145 return ((JS::shadow::Runtime *)runtime_)->gcNurseryStart_;
michael@0 146 }
michael@0 147
michael@0 148 MOZ_ALWAYS_INLINE uintptr_t heapEnd() const {
michael@0 149 JS_ASSERT(runtime_);
michael@0 150 return ((JS::shadow::Runtime *)runtime_)->gcNurseryEnd_;
michael@0 151 }
michael@0 152
michael@0 153 private:
michael@0 154 /*
michael@0 155 * The start and end pointers are stored under the runtime so that we can
michael@0 156 * inline the isInsideNursery check into embedder code. Use the start()
michael@0 157 * and heapEnd() functions to access these values.
michael@0 158 */
michael@0 159 JSRuntime *runtime_;
michael@0 160
michael@0 161 /* Pointer to the first unallocated byte in the nursery. */
michael@0 162 uintptr_t position_;
michael@0 163
michael@0 164 /* Pointer to the logical start of the Nursery. */
michael@0 165 uintptr_t currentStart_;
michael@0 166
michael@0 167 /* Pointer to the last byte of space in the current chunk. */
michael@0 168 uintptr_t currentEnd_;
michael@0 169
michael@0 170 /* The index of the chunk that is currently being allocated from. */
michael@0 171 int currentChunk_;
michael@0 172
michael@0 173 /* The index after the last chunk that we will allocate from. */
michael@0 174 int numActiveChunks_;
michael@0 175
michael@0 176 /*
michael@0 177 * The set of externally malloced slots potentially kept live by objects
michael@0 178 * stored in the nursery. Any external slots that do not belong to a
michael@0 179 * tenured thing at the end of a minor GC must be freed.
michael@0 180 */
michael@0 181 typedef HashSet<HeapSlot *, PointerHasher<HeapSlot *, 3>, SystemAllocPolicy> HugeSlotsSet;
michael@0 182 HugeSlotsSet hugeSlots;
michael@0 183
michael@0 184 /* The maximum number of slots allowed to reside inline in the nursery. */
michael@0 185 static const size_t MaxNurserySlots = 128;
michael@0 186
michael@0 187 /* The amount of space in the mapped nursery available to allocations. */
michael@0 188 static const size_t NurseryChunkUsableSize = gc::ChunkSize - sizeof(gc::ChunkTrailer);
michael@0 189
michael@0 190 struct NurseryChunkLayout {
michael@0 191 char data[NurseryChunkUsableSize];
michael@0 192 gc::ChunkTrailer trailer;
michael@0 193 uintptr_t start() { return uintptr_t(&data); }
michael@0 194 uintptr_t end() { return uintptr_t(&trailer); }
michael@0 195 };
michael@0 196 static_assert(sizeof(NurseryChunkLayout) == gc::ChunkSize,
michael@0 197 "Nursery chunk size must match gc::Chunk size.");
michael@0 198 NurseryChunkLayout &chunk(int index) const {
michael@0 199 JS_ASSERT(index < NumNurseryChunks);
michael@0 200 JS_ASSERT(start());
michael@0 201 return reinterpret_cast<NurseryChunkLayout *>(start())[index];
michael@0 202 }
michael@0 203
michael@0 204 MOZ_ALWAYS_INLINE void initChunk(int chunkno) {
michael@0 205 NurseryChunkLayout &c = chunk(chunkno);
michael@0 206 c.trailer.location = gc::ChunkLocationNursery;
michael@0 207 c.trailer.runtime = runtime();
michael@0 208 }
michael@0 209
michael@0 210 MOZ_ALWAYS_INLINE void setCurrentChunk(int chunkno) {
michael@0 211 JS_ASSERT(chunkno < NumNurseryChunks);
michael@0 212 JS_ASSERT(chunkno < numActiveChunks_);
michael@0 213 currentChunk_ = chunkno;
michael@0 214 position_ = chunk(chunkno).start();
michael@0 215 currentEnd_ = chunk(chunkno).end();
michael@0 216 initChunk(chunkno);
michael@0 217 }
michael@0 218
michael@0 219 void updateDecommittedRegion() {
michael@0 220 #ifndef JS_GC_ZEAL
michael@0 221 if (numActiveChunks_ < NumNurseryChunks) {
michael@0 222 // Bug 994054: madvise on MacOS is too slow to make this
michael@0 223 // optimization worthwhile.
michael@0 224 # ifndef XP_MACOSX
michael@0 225 uintptr_t decommitStart = chunk(numActiveChunks_).start();
michael@0 226 JS_ASSERT(decommitStart == AlignBytes(decommitStart, 1 << 20));
michael@0 227 gc::MarkPagesUnused(runtime(), (void *)decommitStart, heapEnd() - decommitStart);
michael@0 228 # endif
michael@0 229 }
michael@0 230 #endif
michael@0 231 }
michael@0 232
michael@0 233 MOZ_ALWAYS_INLINE uintptr_t allocationEnd() const {
michael@0 234 JS_ASSERT(numActiveChunks_ > 0);
michael@0 235 return chunk(numActiveChunks_ - 1).end();
michael@0 236 }
michael@0 237
michael@0 238 MOZ_ALWAYS_INLINE bool isFullyGrown() const {
michael@0 239 return numActiveChunks_ == NumNurseryChunks;
michael@0 240 }
michael@0 241
michael@0 242 MOZ_ALWAYS_INLINE uintptr_t currentEnd() const {
michael@0 243 JS_ASSERT(runtime_);
michael@0 244 JS_ASSERT(currentEnd_ == chunk(currentChunk_).end());
michael@0 245 return currentEnd_;
michael@0 246 }
michael@0 247 void *addressOfCurrentEnd() const {
michael@0 248 JS_ASSERT(runtime_);
michael@0 249 return (void *)&currentEnd_;
michael@0 250 }
michael@0 251
michael@0 252 uintptr_t position() const { return position_; }
michael@0 253 void *addressOfPosition() const { return (void*)&position_; }
michael@0 254
michael@0 255 JSRuntime *runtime() const { return runtime_; }
michael@0 256
michael@0 257 /* Allocates and registers external slots with the nursery. */
michael@0 258 HeapSlot *allocateHugeSlots(JSContext *cx, size_t nslots);
michael@0 259
michael@0 260 /* Allocates a new GC thing from the tenured generation during minor GC. */
michael@0 261 void *allocateFromTenured(JS::Zone *zone, gc::AllocKind thingKind);
michael@0 262
michael@0 263 struct TenureCountCache;
michael@0 264
michael@0 265 /* Common internal allocator function. */
michael@0 266 void *allocate(size_t size);
michael@0 267
michael@0 268 /*
michael@0 269 * Move the object at |src| in the Nursery to an already-allocated cell
michael@0 270 * |dst| in Tenured.
michael@0 271 */
michael@0 272 void collectToFixedPoint(gc::MinorCollectionTracer *trc, TenureCountCache &tenureCounts);
michael@0 273 MOZ_ALWAYS_INLINE void traceObject(gc::MinorCollectionTracer *trc, JSObject *src);
michael@0 274 MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer *trc, HeapSlot *vp, uint32_t nslots);
michael@0 275 MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer *trc, HeapSlot *vp, HeapSlot *end);
michael@0 276 MOZ_ALWAYS_INLINE void markSlot(gc::MinorCollectionTracer *trc, HeapSlot *slotp);
michael@0 277 void *moveToTenured(gc::MinorCollectionTracer *trc, JSObject *src);
michael@0 278 size_t moveObjectToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
michael@0 279 size_t moveElementsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
michael@0 280 size_t moveSlotsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
michael@0 281 void forwardTypedArrayPointers(JSObject *dst, JSObject *src);
michael@0 282
michael@0 283 /* Handle relocation of slots/elements pointers stored in Ion frames. */
michael@0 284 void setSlotsForwardingPointer(HeapSlot *oldSlots, HeapSlot *newSlots, uint32_t nslots);
michael@0 285 void setElementsForwardingPointer(ObjectElements *oldHeader, ObjectElements *newHeader,
michael@0 286 uint32_t nelems);
michael@0 287
michael@0 288 /* Free malloced pointers owned by freed things in the nursery. */
michael@0 289 void freeHugeSlots(JSRuntime *rt);
michael@0 290
michael@0 291 /*
michael@0 292 * Frees all non-live nursery-allocated things at the end of a minor
michael@0 293 * collection.
michael@0 294 */
michael@0 295 void sweep(JSRuntime *rt);
michael@0 296
michael@0 297 /* Change the allocable space provided by the nursery. */
michael@0 298 void growAllocableSpace();
michael@0 299 void shrinkAllocableSpace();
michael@0 300
michael@0 301 static void MinorGCCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind);
michael@0 302
michael@0 303 #ifdef JS_GC_ZEAL
michael@0 304 /*
michael@0 305 * In debug and zeal builds, these bytes indicate the state of an unused
michael@0 306 * segment of nursery-allocated memory.
michael@0 307 */
michael@0 308 void enterZealMode() {
michael@0 309 if (isEnabled())
michael@0 310 numActiveChunks_ = NumNurseryChunks;
michael@0 311 }
michael@0 312 void leaveZealMode() {
michael@0 313 if (isEnabled()) {
michael@0 314 JS_ASSERT(isEmpty());
michael@0 315 setCurrentChunk(0);
michael@0 316 currentStart_ = start();
michael@0 317 }
michael@0 318 }
michael@0 319 #else
michael@0 320 void enterZealMode() {}
michael@0 321 void leaveZealMode() {}
michael@0 322 #endif
michael@0 323
michael@0 324 friend class gc::MinorCollectionTracer;
michael@0 325 friend class jit::MacroAssembler;
michael@0 326 friend void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
michael@0 327 };
michael@0 328
michael@0 329 } /* namespace js */
michael@0 330
michael@0 331 #endif /* JSGC_GENERATIONAL */
michael@0 332 #endif /* gc_Nursery_h */

mercurial