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