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 68696813 : GetGCThingTraceKind(const void *thing)
60 : {
61 68696813 : JS_ASSERT(thing);
62 68696813 : const Cell *cell = reinterpret_cast<const Cell *>(thing);
63 68696813 : 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 11147671 : GetGCObjectKind(size_t numSlots)
72 : {
73 : extern AllocKind slotsToThingKind[];
74 :
75 11147671 : if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
76 249154 : return FINALIZE_OBJECT16;
77 10898517 : return slotsToThingKind[numSlots];
78 : }
79 :
80 : static inline AllocKind
81 8818707 : GetGCObjectKind(Class *clasp)
82 : {
83 8818707 : if (clasp == &FunctionClass)
84 70887 : return JSFunction::FinalizeKind;
85 8747820 : uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
86 8747820 : if (clasp->flags & JSCLASS_HAS_PRIVATE)
87 589502 : nslots++;
88 8747820 : return GetGCObjectKind(nslots);
89 : }
90 :
91 : /* As for GetGCObjectKind, but for dense array allocation. */
92 : static inline AllocKind
93 2124663 : 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 2124663 : if (numSlots > JSObject::NELEMENTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT)
105 28853 : return FINALIZE_OBJECT2;
106 2095810 : return slotsToThingKind[numSlots + 2];
107 : }
108 :
109 : static inline AllocKind
110 2614024 : GetGCObjectFixedSlotsKind(size_t numFixedSlots)
111 : {
112 : extern AllocKind slotsToThingKind[];
113 :
114 2614024 : JS_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
115 2614024 : return slotsToThingKind[numFixedSlots];
116 : }
117 :
118 : static inline bool
119 39375651 : IsBackgroundAllocKind(AllocKind kind)
120 : {
121 39375651 : JS_ASSERT(kind <= FINALIZE_LAST);
122 39375651 : return kind <= FINALIZE_OBJECT_LAST && kind % 2 == 1;
123 : }
124 :
125 : static inline AllocKind
126 15101080 : GetBackgroundAllocKind(AllocKind kind)
127 : {
128 15101080 : JS_ASSERT(!IsBackgroundAllocKind(kind));
129 15101080 : 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 17354293 : GetGCKindSlots(AllocKind thingKind)
149 : {
150 : /* Using a switch in hopes that thingKind will usually be a compile-time constant. */
151 17354293 : switch (thingKind) {
152 : case FINALIZE_OBJECT0:
153 : case FINALIZE_OBJECT0_BACKGROUND:
154 797009 : return 0;
155 : case FINALIZE_OBJECT2:
156 : case FINALIZE_OBJECT2_BACKGROUND:
157 9763801 : return 2;
158 : case FINALIZE_OBJECT4:
159 : case FINALIZE_OBJECT4_BACKGROUND:
160 3852578 : return 4;
161 : case FINALIZE_OBJECT8:
162 : case FINALIZE_OBJECT8_BACKGROUND:
163 699466 : return 8;
164 : case FINALIZE_OBJECT12:
165 : case FINALIZE_OBJECT12_BACKGROUND:
166 1664084 : return 12;
167 : case FINALIZE_OBJECT16:
168 : case FINALIZE_OBJECT16_BACKGROUND:
169 577355 : 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 15166497 : GetGCKindSlots(AllocKind thingKind, Class *clasp)
178 : {
179 15166497 : size_t nslots = GetGCKindSlots(thingKind);
180 :
181 : /* An object's private data uses the space taken by its last fixed slot. */
182 15166497 : if (clasp->flags & JSCLASS_HAS_PRIVATE) {
183 2829874 : JS_ASSERT(nslots > 0);
184 2829874 : 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 15166497 : if (clasp == &FunctionClass)
192 8631365 : nslots = 0;
193 :
194 15166497 : return nslots;
195 : }
196 :
197 : static inline void
198 2709 : 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 2709 : 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 2709 : if (rt->gcZeal() == js::gc::ZealPokeValue)
214 0 : rt->gcNextScheduled = 1;
215 : #endif
216 2709 : }
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 83677 : ForEachArenaAndCell(JSCompartment *compartment, AllocKind thingKind,
225 : ArenaOp arenaOp, CellOp cellOp)
226 : {
227 83677 : size_t thingSize = Arena::thingSize(thingKind);
228 83677 : ArenaHeader *aheader = compartment->arenas.getFirstArena(thingKind);
229 :
230 128983 : for (; aheader; aheader = aheader->next) {
231 45306 : Arena *arena = aheader->getArena();
232 45306 : arenaOp(arena);
233 45306 : FreeSpan firstSpan(aheader->getFirstFreeSpan());
234 45306 : const FreeSpan *span = &firstSpan;
235 :
236 827014 : for (uintptr_t thing = arena->thingsStart(thingKind); ; thing += thingSize) {
237 827014 : JS_ASSERT(thing <= arena->thingsEnd());
238 827014 : if (thing == span->first) {
239 59115 : if (!span->hasNext())
240 : break;
241 13809 : thing = span->last;
242 13809 : span = span->nextSpan();
243 : } else {
244 767899 : Cell *t = reinterpret_cast<Cell *>(thing);
245 767899 : cellOp(t);
246 : }
247 : }
248 : }
249 83677 : }
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 268346 : CellIterImpl() {
263 268346 : }
264 :
265 268346 : void initSpan(JSCompartment *comp, AllocKind kind) {
266 268346 : JS_ASSERT(comp->arenas.isSynchronizedFreeList(kind));
267 268346 : firstThingOffset = Arena::firstThingOffset(kind);
268 268346 : thingSize = Arena::thingSize(kind);
269 268346 : firstSpan.initAsEmpty();
270 268346 : span = &firstSpan;
271 268346 : thing = span->first;
272 268346 : }
273 :
274 9 : void init(ArenaHeader *singleAheader) {
275 9 : aheader = singleAheader;
276 9 : initSpan(aheader->compartment, aheader->getAllocKind());
277 9 : next();
278 9 : aheader = NULL;
279 9 : }
280 :
281 268337 : void init(JSCompartment *comp, AllocKind kind) {
282 268337 : initSpan(comp, kind);
283 268337 : aheader = comp->arenas.getFirstArena(kind);
284 268337 : next();
285 268337 : }
286 :
287 : public:
288 3216883 : bool done() const {
289 3216883 : return !cell;
290 : }
291 :
292 1477930 : template<typename T> T *get() const {
293 1477930 : JS_ASSERT(!done());
294 1477930 : return static_cast<T *>(cell);
295 : }
296 :
297 0 : Cell *getCell() const {
298 0 : JS_ASSERT(!done());
299 0 : return cell;
300 : }
301 :
302 1910576 : void next() {
303 171623 : for (;;) {
304 1910576 : if (thing != span->first)
305 1407124 : break;
306 503452 : if (JS_LIKELY(span->hasNext())) {
307 63483 : thing = span->last + thingSize;
308 63483 : span = span->nextSpan();
309 63483 : break;
310 : }
311 439969 : if (!aheader) {
312 268346 : cell = NULL;
313 268346 : return;
314 : }
315 171623 : firstSpan = aheader->getFirstFreeSpan();
316 171623 : span = &firstSpan;
317 171623 : thing = aheader->arenaAddress() | firstThingOffset;
318 171623 : aheader = aheader->next;
319 : }
320 1470607 : cell = reinterpret_cast<Cell *>(thing);
321 1470607 : thing += thingSize;
322 : }
323 : };
324 :
325 : class CellIterUnderGC : public CellIterImpl
326 : {
327 : public:
328 215018 : CellIterUnderGC(JSCompartment *comp, AllocKind kind) {
329 215018 : JS_ASSERT(comp->rt->gcRunning);
330 215018 : init(comp, kind);
331 215018 : }
332 :
333 9 : CellIterUnderGC(ArenaHeader *aheader) {
334 9 : JS_ASSERT(aheader->compartment->rt->gcRunning);
335 9 : init(aheader);
336 9 : }
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 53319 : CellIter(JSCompartment *comp, AllocKind kind)
353 : : lists(&comp->arenas),
354 53319 : 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 53319 : JS_ASSERT(!IsBackgroundAllocKind(kind));
363 53319 : if (lists->isSynchronizedFreeList(kind)) {
364 22606 : lists = NULL;
365 : } else {
366 30713 : JS_ASSERT(!comp->rt->gcRunning);
367 30713 : lists->copyFreeListToArena(kind);
368 : }
369 : #ifdef DEBUG
370 53319 : counter = &comp->rt->noGCOrAllocationCheck;
371 53319 : ++*counter;
372 : #endif
373 53319 : init(comp, kind);
374 53319 : }
375 :
376 53319 : ~CellIter() {
377 : #ifdef DEBUG
378 53319 : JS_ASSERT(*counter > 0);
379 53319 : --*counter;
380 : #endif
381 53319 : if (lists)
382 30713 : lists->clearFreeListInArena(kind);
383 53319 : }
384 : };
385 :
386 : /* Signatures for ArenaOp and CellOp above. */
387 :
388 45306 : inline void EmptyArenaOp(Arena *arena) {}
389 : inline void EmptyCellOp(Cell *t) {}
390 :
391 : class GCCompartmentsIter {
392 : private:
393 : JSCompartment **it, **end;
394 :
395 : public:
396 423251 : GCCompartmentsIter(JSRuntime *rt) {
397 423251 : JS_ASSERT(rt->gcRunning);
398 423251 : it = rt->compartments.begin();
399 423251 : end = rt->compartments.end();
400 423251 : if (!(*it)->isCollecting())
401 1773 : next();
402 423251 : JS_ASSERT(it < end);
403 423251 : }
404 :
405 3125087 : bool done() const { return it == end; }
406 :
407 901605 : void next() {
408 901605 : JS_ASSERT(!done());
409 1382983 : do {
410 903117 : it++;
411 479866 : } while (it != end && !(*it)->isCollecting());
412 901605 : }
413 :
414 900399 : JSCompartment *get() const {
415 900399 : JS_ASSERT(!done());
416 900399 : return *it;
417 : }
418 :
419 83697 : operator JSCompartment *() const { return get(); }
420 816702 : JSCompartment *operator->() const { return get(); }
421 : };
422 :
423 : /*
424 : * Allocates a new GC thing. After a successful allocation the caller must
425 : * fully initialize the thing before calling any function that can potentially
426 : * trigger GC. This will ensure that GC tracing never sees junk values stored
427 : * in the partially initialized thing.
428 : */
429 :
430 : template <typename T>
431 : inline T *
432 194981538 : NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
433 : {
434 194981538 : JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
435 : #ifdef JS_THREADSAFE
436 194981538 : JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
437 : kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
438 : #endif
439 194981538 : JS_ASSERT(!cx->runtime->gcRunning);
440 194981538 : JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
441 :
442 : /* For testing out of memory conditions */
443 194981538 : JS_OOM_POSSIBLY_FAIL();
444 :
445 : #ifdef JS_GC_ZEAL
446 194981538 : if (cx->runtime->needZealousGC())
447 10664 : js::gc::RunDebugGC(cx);
448 : #endif
449 :
450 194981538 : js::gc::MaybeCheckStackRoots(cx);
451 :
452 194981538 : JSCompartment *comp = cx->compartment;
453 194981538 : void *t = comp->arenas.allocateFromFreeList(kind, thingSize);
454 194981538 : if (!t)
455 1768475 : t = js::gc::ArenaLists::refillFreeList(cx, kind);
456 :
457 194981538 : JS_ASSERT_IF(t && comp->needsBarrier(),
458 : static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
459 194981538 : return static_cast<T *>(t);
460 : }
461 :
462 : /* Alternate form which allocates a GC thing if doing so cannot trigger a GC. */
463 : template <typename T>
464 : inline T *
465 19052050 : TryNewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
466 : {
467 19052050 : JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
468 : #ifdef JS_THREADSAFE
469 19052050 : JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
470 : kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
471 : #endif
472 19052050 : JS_ASSERT(!cx->runtime->gcRunning);
473 19052050 : JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
474 :
475 : #ifdef JS_GC_ZEAL
476 19052050 : if (cx->runtime->needZealousGC())
477 1570 : return NULL;
478 : #endif
479 :
480 19050480 : void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize);
481 19050480 : JS_ASSERT_IF(t && cx->compartment->needsBarrier(),
482 : static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
483 19050480 : return static_cast<T *>(t);
484 : }
485 :
486 : } /* namespace gc */
487 : } /* namespace js */
488 :
489 : inline JSObject *
490 7024695 : js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
491 : {
492 7024695 : JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
493 7024695 : return js::gc::NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
494 : }
495 :
496 : inline JSObject *
497 19052050 : js_TryNewGCObject(JSContext *cx, js::gc::AllocKind kind)
498 : {
499 19052050 : JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
500 19052050 : return js::gc::TryNewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
501 : }
502 :
503 : inline JSString *
504 112031904 : js_NewGCString(JSContext *cx)
505 : {
506 112031904 : return js::gc::NewGCThing<JSString>(cx, js::gc::FINALIZE_STRING, sizeof(JSString));
507 : }
508 :
509 : inline JSShortString *
510 46323244 : js_NewGCShortString(JSContext *cx)
511 : {
512 46323244 : return js::gc::NewGCThing<JSShortString>(cx, js::gc::FINALIZE_SHORT_STRING, sizeof(JSShortString));
513 : }
514 :
515 : inline JSExternalString *
516 2000 : js_NewGCExternalString(JSContext *cx)
517 : {
518 : return js::gc::NewGCThing<JSExternalString>(cx, js::gc::FINALIZE_EXTERNAL_STRING,
519 2000 : sizeof(JSExternalString));
520 : }
521 :
522 : inline JSScript *
523 285135 : js_NewGCScript(JSContext *cx)
524 : {
525 285135 : return js::gc::NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
526 : }
527 :
528 : inline js::Shape *
529 20149251 : js_NewGCShape(JSContext *cx)
530 : {
531 20149251 : return js::gc::NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
532 : }
533 :
534 : inline js::BaseShape *
535 4089976 : js_NewGCBaseShape(JSContext *cx)
536 : {
537 4089976 : return js::gc::NewGCThing<js::BaseShape>(cx, js::gc::FINALIZE_BASE_SHAPE, sizeof(js::BaseShape));
538 : }
539 :
540 : #if JS_HAS_XML_SUPPORT
541 : extern JSXML *
542 : js_NewGCXML(JSContext *cx);
543 : #endif
544 :
545 : #endif /* jsgcinlines_h___ */
|