js/src/gc/Nursery.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:1751daab0c89
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/. */
7
8 #ifndef gc_Nursery_h
9 #define gc_Nursery_h
10
11 #ifdef JSGC_GENERATIONAL
12
13 #include "jsalloc.h"
14 #include "jspubtd.h"
15
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"
24
25 namespace JS {
26 struct Zone;
27 }
28
29 namespace js {
30
31 class ObjectElements;
32 class HeapSlot;
33 void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
34
35 namespace gc {
36 class Cell;
37 class MinorCollectionTracer;
38 } /* namespace gc */
39
40 namespace types {
41 struct TypeObject;
42 }
43
44 namespace jit {
45 class CodeGenerator;
46 class MacroAssembler;
47 class ICStubCompiler;
48 class BaselineCompiler;
49 }
50
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;
59
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();
69
70 bool init();
71
72 void enable();
73 void disable();
74 bool isEnabled() const { return numActiveChunks_ != 0; }
75
76 /* Return true if no allocations have been made since the last collection. */
77 bool isEmpty() const;
78
79 template <typename T>
80 MOZ_ALWAYS_INLINE bool isInside(const T *p) const {
81 return gc::IsInsideNursery((JS::shadow::Runtime *)runtime_, p);
82 }
83
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);
89
90 /* Allocate a slots array for the given object. */
91 HeapSlot *allocateSlots(JSContext *cx, JSObject *obj, uint32_t nslots);
92
93 /* Allocate an elements vector for the given object. */
94 ObjectElements *allocateElements(JSContext *cx, JSObject *obj, uint32_t nelems);
95
96 /* Resize an existing slots array. */
97 HeapSlot *reallocateSlots(JSContext *cx, JSObject *obj, HeapSlot *oldSlots,
98 uint32_t oldCount, uint32_t newCount);
99
100 /* Resize an existing elements vector. */
101 ObjectElements *reallocateElements(JSContext *cx, JSObject *obj, ObjectElements *oldHeader,
102 uint32_t oldCount, uint32_t newCount);
103
104 /* Free a slots array. */
105 void freeSlots(JSContext *cx, HeapSlot *slots);
106
107 /* Add a slots to our tracking list if it is out-of-line. */
108 void notifyInitialSlots(gc::Cell *cell, HeapSlot *slots);
109
110 typedef Vector<types::TypeObject *, 0, SystemAllocPolicy> TypeObjectList;
111
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);
117
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);
125
126 /* Forward a slots/elements pointer stored in an Ion frame. */
127 void forwardBufferPointer(HeapSlot **pSlotsElems);
128
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 }
142
143 MOZ_ALWAYS_INLINE uintptr_t start() const {
144 JS_ASSERT(runtime_);
145 return ((JS::shadow::Runtime *)runtime_)->gcNurseryStart_;
146 }
147
148 MOZ_ALWAYS_INLINE uintptr_t heapEnd() const {
149 JS_ASSERT(runtime_);
150 return ((JS::shadow::Runtime *)runtime_)->gcNurseryEnd_;
151 }
152
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_;
160
161 /* Pointer to the first unallocated byte in the nursery. */
162 uintptr_t position_;
163
164 /* Pointer to the logical start of the Nursery. */
165 uintptr_t currentStart_;
166
167 /* Pointer to the last byte of space in the current chunk. */
168 uintptr_t currentEnd_;
169
170 /* The index of the chunk that is currently being allocated from. */
171 int currentChunk_;
172
173 /* The index after the last chunk that we will allocate from. */
174 int numActiveChunks_;
175
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;
183
184 /* The maximum number of slots allowed to reside inline in the nursery. */
185 static const size_t MaxNurserySlots = 128;
186
187 /* The amount of space in the mapped nursery available to allocations. */
188 static const size_t NurseryChunkUsableSize = gc::ChunkSize - sizeof(gc::ChunkTrailer);
189
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 }
203
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 }
209
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 }
218
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 }
232
233 MOZ_ALWAYS_INLINE uintptr_t allocationEnd() const {
234 JS_ASSERT(numActiveChunks_ > 0);
235 return chunk(numActiveChunks_ - 1).end();
236 }
237
238 MOZ_ALWAYS_INLINE bool isFullyGrown() const {
239 return numActiveChunks_ == NumNurseryChunks;
240 }
241
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 *)&currentEnd_;
250 }
251
252 uintptr_t position() const { return position_; }
253 void *addressOfPosition() const { return (void*)&position_; }
254
255 JSRuntime *runtime() const { return runtime_; }
256
257 /* Allocates and registers external slots with the nursery. */
258 HeapSlot *allocateHugeSlots(JSContext *cx, size_t nslots);
259
260 /* Allocates a new GC thing from the tenured generation during minor GC. */
261 void *allocateFromTenured(JS::Zone *zone, gc::AllocKind thingKind);
262
263 struct TenureCountCache;
264
265 /* Common internal allocator function. */
266 void *allocate(size_t size);
267
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);
282
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);
287
288 /* Free malloced pointers owned by freed things in the nursery. */
289 void freeHugeSlots(JSRuntime *rt);
290
291 /*
292 * Frees all non-live nursery-allocated things at the end of a minor
293 * collection.
294 */
295 void sweep(JSRuntime *rt);
296
297 /* Change the allocable space provided by the nursery. */
298 void growAllocableSpace();
299 void shrinkAllocableSpace();
300
301 static void MinorGCCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind);
302
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
323
324 friend class gc::MinorCollectionTracer;
325 friend class jit::MacroAssembler;
326 friend void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
327 };
328
329 } /* namespace js */
330
331 #endif /* JSGC_GENERATIONAL */
332 #endif /* gc_Nursery_h */

mercurial