1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is SpiderMonkey code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef jsgcinlines_h___
41 : #define jsgcinlines_h___
42 :
43 : #include "jsgc.h"
44 : #include "jscntxt.h"
45 : #include "jscompartment.h"
46 : #include "jslock.h"
47 : #include "jsscope.h"
48 : #include "jsxml.h"
49 :
50 : #include "js/TemplateLib.h"
51 :
52 : namespace js {
53 :
54 : struct Shape;
55 :
56 : namespace gc {
57 :
58 : inline JSGCTraceKind
59 89948620 : GetGCThingTraceKind(const void *thing)
60 : {
61 89948620 : JS_ASSERT(thing);
62 89948620 : const Cell *cell = reinterpret_cast<const Cell *>(thing);
63 89948620 : return MapAllocToTraceKind(cell->getAllocKind());
64 : }
65 :
66 : /* Capacity for slotsToThingKind */
67 : const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
68 :
69 : /* Get the best kind to use when making an object with the given slot count. */
70 : static inline AllocKind
71 22938476 : GetGCObjectKind(size_t numSlots)
72 : {
73 : extern AllocKind slotsToThingKind[];
74 :
75 22938476 : if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
76 289842 : return FINALIZE_OBJECT16;
77 22648634 : return slotsToThingKind[numSlots];
78 : }
79 :
80 : static inline AllocKind
81 15443903 : GetGCObjectKind(Class *clasp)
82 : {
83 15443903 : if (clasp == &FunctionClass)
84 115911 : return JSFunction::FinalizeKind;
85 15327992 : uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
86 15327992 : if (clasp->flags & JSCLASS_HAS_PRIVATE)
87 2489547 : nslots++;
88 15327992 : return GetGCObjectKind(nslots);
89 : }
90 :
91 : /* As for GetGCObjectKind, but for dense array allocation. */
92 : static inline AllocKind
93 2558224 : GetGCArrayKind(size_t numSlots)
94 : {
95 : extern AllocKind slotsToThingKind[];
96 :
97 : /*
98 : * Dense arrays can use their fixed slots to hold their elements array
99 : * (less two Values worth of ObjectElements header), but if more than the
100 : * maximum number of fixed slots is needed then the fixed slots will be
101 : * unused.
102 : */
103 : JS_STATIC_ASSERT(ObjectElements::VALUES_PER_HEADER == 2);
104 2558224 : if (numSlots > JSObject::NELEMENTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT)
105 103352 : return FINALIZE_OBJECT2;
106 2454872 : return slotsToThingKind[numSlots + 2];
107 : }
108 :
109 : static inline AllocKind
110 2613913 : GetGCObjectFixedSlotsKind(size_t numFixedSlots)
111 : {
112 : extern AllocKind slotsToThingKind[];
113 :
114 2613913 : JS_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
115 2613913 : return slotsToThingKind[numFixedSlots];
116 : }
117 :
118 : static inline bool
119 53376477 : IsBackgroundAllocKind(AllocKind kind)
120 : {
121 53376477 : JS_ASSERT(kind <= FINALIZE_LAST);
122 53376477 : return kind <= FINALIZE_OBJECT_LAST && kind % 2 == 1;
123 : }
124 :
125 : static inline AllocKind
126 15552536 : GetBackgroundAllocKind(AllocKind kind)
127 : {
128 15552536 : JS_ASSERT(!IsBackgroundAllocKind(kind));
129 15552536 : return (AllocKind) (kind + 1);
130 : }
131 :
132 : /*
133 : * Try to get the next larger size for an object, keeping BACKGROUND
134 : * consistent.
135 : */
136 : static inline bool
137 17 : TryIncrementAllocKind(AllocKind *kindp)
138 : {
139 17 : size_t next = size_t(*kindp) + 2;
140 17 : if (next >= size_t(FINALIZE_OBJECT_LIMIT))
141 0 : return false;
142 17 : *kindp = AllocKind(next);
143 17 : return true;
144 : }
145 :
146 : /* Get the number of fixed slots and initial capacity associated with a kind. */
147 : static inline size_t
148 38120267 : GetGCKindSlots(AllocKind thingKind)
149 : {
150 : /* Using a switch in hopes that thingKind will usually be a compile-time constant. */
151 38120267 : switch (thingKind) {
152 : case FINALIZE_OBJECT0:
153 : case FINALIZE_OBJECT0_BACKGROUND:
154 1949371 : return 0;
155 : case FINALIZE_OBJECT2:
156 : case FINALIZE_OBJECT2_BACKGROUND:
157 19279947 : return 2;
158 : case FINALIZE_OBJECT4:
159 : case FINALIZE_OBJECT4_BACKGROUND:
160 11538849 : return 4;
161 : case FINALIZE_OBJECT8:
162 : case FINALIZE_OBJECT8_BACKGROUND:
163 2649692 : return 8;
164 : case FINALIZE_OBJECT12:
165 : case FINALIZE_OBJECT12_BACKGROUND:
166 1991414 : return 12;
167 : case FINALIZE_OBJECT16:
168 : case FINALIZE_OBJECT16_BACKGROUND:
169 710994 : return 16;
170 : default:
171 0 : JS_NOT_REACHED("Bad object finalize kind");
172 : return 0;
173 : }
174 : }
175 :
176 : static inline size_t
177 28708598 : GetGCKindSlots(AllocKind thingKind, Class *clasp)
178 : {
179 28708598 : size_t nslots = GetGCKindSlots(thingKind);
180 :
181 : /* An object's private data uses the space taken by its last fixed slot. */
182 28708598 : if (clasp->flags & JSCLASS_HAS_PRIVATE) {
183 7918939 : JS_ASSERT(nslots > 0);
184 7918939 : nslots--;
185 : }
186 :
187 : /*
188 : * Functions have a larger finalize kind than FINALIZE_OBJECT to reserve
189 : * space for the extra fields in JSFunction, but have no fixed slots.
190 : */
191 28708598 : if (clasp == &FunctionClass)
192 16039372 : nslots = 0;
193 :
194 28708598 : return nslots;
195 : }
196 :
197 : static inline void
198 21124 : GCPoke(JSRuntime *rt, Value oldval)
199 : {
200 : /*
201 : * Since we're forcing a GC from JS_GC anyway, don't bother wasting cycles
202 : * loading oldval. XXX remove implied force, fix jsinterp.c's "second arg
203 : * ignored", etc.
204 : */
205 : #if 1
206 21124 : rt->gcPoke = true;
207 : #else
208 : rt->gcPoke = oldval.isGCThing();
209 : #endif
210 :
211 : #ifdef JS_GC_ZEAL
212 : /* Schedule a GC to happen "soon" after a GC poke. */
213 21124 : if (rt->gcZeal() == js::gc::ZealPokeValue)
214 0 : rt->gcNextScheduled = 1;
215 : #endif
216 21124 : }
217 :
218 : /*
219 : * Invoke ArenaOp and CellOp on every arena and cell in a compartment which
220 : * have the specified thing kind.
221 : */
222 : template <class ArenaOp, class CellOp>
223 : void
224 122622 : ForEachArenaAndCell(JSCompartment *compartment, AllocKind thingKind,
225 : ArenaOp arenaOp, CellOp cellOp)
226 : {
227 122622 : size_t thingSize = Arena::thingSize(thingKind);
228 122622 : ArenaHeader *aheader = compartment->arenas.getFirstArena(thingKind);
229 :
230 204583 : for (; aheader; aheader = aheader->next) {
231 81961 : Arena *arena = aheader->getArena();
232 81961 : arenaOp(arena);
233 81961 : FreeSpan firstSpan(aheader->getFirstFreeSpan());
234 81961 : const FreeSpan *span = &firstSpan;
235 :
236 3159017 : for (uintptr_t thing = arena->thingsStart(thingKind); ; thing += thingSize) {
237 3159017 : JS_ASSERT(thing <= arena->thingsEnd());
238 3159017 : if (thing == span->first) {
239 245337 : if (!span->hasNext())
240 : break;
241 163376 : thing = span->last;
242 163376 : span = span->nextSpan();
243 : } else {
244 2913680 : Cell *t = reinterpret_cast<Cell *>(thing);
245 2913680 : cellOp(t);
246 : }
247 : }
248 : }
249 122622 : }
250 :
251 : class CellIterImpl
252 : {
253 : size_t firstThingOffset;
254 : size_t thingSize;
255 : ArenaHeader *aheader;
256 : FreeSpan firstSpan;
257 : const FreeSpan *span;
258 : uintptr_t thing;
259 : Cell *cell;
260 :
261 : protected:
262 358274 : CellIterImpl() {
263 358274 : }
264 :
265 358274 : void initSpan(JSCompartment *comp, AllocKind kind) {
266 358274 : JS_ASSERT(comp->arenas.isSynchronizedFreeList(kind));
267 358274 : firstThingOffset = Arena::firstThingOffset(kind);
268 358274 : thingSize = Arena::thingSize(kind);
269 358274 : firstSpan.initAsEmpty();
270 358274 : span = &firstSpan;
271 358274 : thing = span->first;
272 358274 : }
273 :
274 0 : void init(ArenaHeader *singleAheader) {
275 0 : aheader = singleAheader;
276 0 : initSpan(aheader->compartment, aheader->getAllocKind());
277 0 : next();
278 0 : aheader = NULL;
279 0 : }
280 :
281 358274 : void init(JSCompartment *comp, AllocKind kind) {
282 358274 : initSpan(comp, kind);
283 358274 : aheader = comp->arenas.getFirstArena(kind);
284 358274 : next();
285 358274 : }
286 :
287 : public:
288 58456381 : bool done() const {
289 58456381 : return !cell;
290 : }
291 :
292 29055088 : template<typename T> T *get() const {
293 29055088 : JS_ASSERT(!done());
294 29055088 : return static_cast<T *>(cell);
295 : }
296 :
297 0 : Cell *getCell() const {
298 0 : JS_ASSERT(!done());
299 0 : return cell;
300 : }
301 :
302 30792631 : void next() {
303 1391338 : for (;;) {
304 30792631 : if (thing != span->first)
305 28454491 : break;
306 2338140 : if (JS_LIKELY(span->hasNext())) {
307 588528 : thing = span->last + thingSize;
308 588528 : span = span->nextSpan();
309 588528 : break;
310 : }
311 1749612 : if (!aheader) {
312 358274 : cell = NULL;
313 358274 : return;
314 : }
315 1391338 : firstSpan = aheader->getFirstFreeSpan();
316 1391338 : span = &firstSpan;
317 1391338 : thing = aheader->arenaAddress() | firstThingOffset;
318 1391338 : aheader = aheader->next;
319 : }
320 29043019 : cell = reinterpret_cast<Cell *>(thing);
321 29043019 : thing += thingSize;
322 : }
323 : };
324 :
325 : class CellIterUnderGC : public CellIterImpl
326 : {
327 : public:
328 291482 : CellIterUnderGC(JSCompartment *comp, AllocKind kind) {
329 291482 : JS_ASSERT(comp->rt->gcRunning);
330 291482 : init(comp, kind);
331 291482 : }
332 :
333 0 : CellIterUnderGC(ArenaHeader *aheader) {
334 0 : JS_ASSERT(aheader->compartment->rt->gcRunning);
335 0 : init(aheader);
336 0 : }
337 : };
338 :
339 : /*
340 : * When using the iterator outside the GC the caller must ensure that no GC or
341 : * allocations of GC things are possible and that the background finalization
342 : * for the given thing kind is not enabled or is done.
343 : */
344 : class CellIter : public CellIterImpl
345 : {
346 : ArenaLists *lists;
347 : AllocKind kind;
348 : #ifdef DEBUG
349 : size_t *counter;
350 : #endif
351 : public:
352 66792 : CellIter(JSCompartment *comp, AllocKind kind)
353 : : lists(&comp->arenas),
354 66792 : kind(kind)
355 : {
356 : /*
357 : * We have a single-threaded runtime, so there's no need to protect
358 : * against other threads iterating or allocating. However, we do have
359 : * background finalization; make sure people aren't using CellIter to
360 : * walk such allocation kinds.
361 : */
362 66792 : JS_ASSERT(!IsBackgroundAllocKind(kind));
363 66792 : if (lists->isSynchronizedFreeList(kind)) {
364 34807 : lists = NULL;
365 : } else {
366 31985 : JS_ASSERT(!comp->rt->gcRunning);
367 31985 : lists->copyFreeListToArena(kind);
368 : }
369 : #ifdef DEBUG
370 66792 : counter = &comp->rt->noGCOrAllocationCheck;
371 66792 : ++*counter;
372 : #endif
373 66792 : init(comp, kind);
374 66792 : }
375 :
376 66792 : ~CellIter() {
377 : #ifdef DEBUG
378 66792 : JS_ASSERT(*counter > 0);
379 66792 : --*counter;
380 : #endif
381 66792 : if (lists)
382 31985 : lists->clearFreeListInArena(kind);
383 66792 : }
384 : };
385 :
386 : /* Signatures for ArenaOp and CellOp above. */
387 :
388 80872 : inline void EmptyArenaOp(Arena *arena) {}
389 : inline void EmptyCellOp(Cell *t) {}
390 :
391 : /*
392 : * Allocates a new GC thing. After a successful allocation the caller must
393 : * fully initialize the thing before calling any function that can potentially
394 : * trigger GC. This will ensure that GC tracing never sees junk values stored
395 : * in the partially initialized thing.
396 : */
397 :
398 : template <typename T>
399 : inline T *
400 241631423 : NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
401 : {
402 241631423 : JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
403 : #ifdef JS_THREADSAFE
404 241631423 : JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
405 : kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
406 : #endif
407 241631423 : JS_ASSERT(!cx->runtime->gcRunning);
408 241631423 : JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
409 :
410 : /* For testing out of memory conditions */
411 241631423 : JS_OOM_POSSIBLY_FAIL();
412 :
413 : #ifdef JS_GC_ZEAL
414 241631423 : if (cx->runtime->needZealousGC())
415 9042 : js::gc::RunDebugGC(cx);
416 : #endif
417 :
418 241631423 : js::gc::MaybeCheckStackRoots(cx);
419 :
420 241631416 : JSCompartment *comp = cx->compartment;
421 241631416 : void *t = comp->arenas.allocateFromFreeList(kind, thingSize);
422 241631417 : if (!t)
423 2339906 : t = js::gc::ArenaLists::refillFreeList(cx, kind);
424 :
425 241631417 : JS_ASSERT_IF(t && comp->needsBarrier(),
426 : static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
427 241631417 : return static_cast<T *>(t);
428 : }
429 :
430 : /* Alternate form which allocates a GC thing if doing so cannot trigger a GC. */
431 : template <typename T>
432 : inline T *
433 28743683 : TryNewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
434 : {
435 28743683 : JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
436 : #ifdef JS_THREADSAFE
437 28743683 : JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
438 : kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
439 : #endif
440 28743683 : JS_ASSERT(!cx->runtime->gcRunning);
441 28743683 : JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
442 :
443 : #ifdef JS_GC_ZEAL
444 28743683 : if (cx->runtime->needZealousGC())
445 1506 : return NULL;
446 : #endif
447 :
448 28742177 : void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize);
449 28742177 : JS_ASSERT_IF(t && cx->compartment->needsBarrier(),
450 : static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
451 28742177 : return static_cast<T *>(t);
452 : }
453 :
454 : } /* namespace gc */
455 : } /* namespace js */
456 :
457 : inline JSObject *
458 11857167 : js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
459 : {
460 11857167 : JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
461 11857167 : return js::gc::NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
462 : }
463 :
464 : inline JSObject *
465 28743683 : js_TryNewGCObject(JSContext *cx, js::gc::AllocKind kind)
466 : {
467 28743683 : JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
468 28743683 : return js::gc::TryNewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
469 : }
470 :
471 : inline JSString *
472 129036224 : js_NewGCString(JSContext *cx)
473 : {
474 129036224 : return js::gc::NewGCThing<JSString>(cx, js::gc::FINALIZE_STRING, sizeof(JSString));
475 : }
476 :
477 : inline JSShortString *
478 52757012 : js_NewGCShortString(JSContext *cx)
479 : {
480 52757012 : return js::gc::NewGCThing<JSShortString>(cx, js::gc::FINALIZE_SHORT_STRING, sizeof(JSShortString));
481 : }
482 :
483 : inline JSExternalString *
484 977008 : js_NewGCExternalString(JSContext *cx)
485 : {
486 : return js::gc::NewGCThing<JSExternalString>(cx, js::gc::FINALIZE_EXTERNAL_STRING,
487 977008 : sizeof(JSExternalString));
488 : }
489 :
490 : inline JSScript *
491 1324850 : js_NewGCScript(JSContext *cx)
492 : {
493 1324850 : return js::gc::NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
494 : }
495 :
496 : inline js::Shape *
497 32712764 : js_NewGCShape(JSContext *cx)
498 : {
499 32712764 : return js::gc::NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
500 : }
501 :
502 : inline js::BaseShape *
503 7567456 : js_NewGCBaseShape(JSContext *cx)
504 : {
505 7567456 : return js::gc::NewGCThing<js::BaseShape>(cx, js::gc::FINALIZE_BASE_SHAPE, sizeof(js::BaseShape));
506 : }
507 :
508 : #if JS_HAS_XML_SUPPORT
509 : extern JSXML *
510 : js_NewGCXML(JSContext *cx);
511 : #endif
512 :
513 : #endif /* jsgcinlines_h___ */
|