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 92674687 : GetGCThingTraceKind(const void *thing)
60 : {
61 92674687 : JS_ASSERT(thing);
62 92674687 : const Cell *cell = reinterpret_cast<const Cell *>(thing);
63 92674687 : 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 22915692 : GetGCObjectKind(size_t numSlots)
72 : {
73 : extern AllocKind slotsToThingKind[];
74 :
75 22915692 : if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
76 289727 : return FINALIZE_OBJECT16;
77 22625965 : return slotsToThingKind[numSlots];
78 : }
79 :
80 : static inline AllocKind
81 15444429 : GetGCObjectKind(Class *clasp)
82 : {
83 15444429 : if (clasp == &FunctionClass)
84 115656 : return JSFunction::FinalizeKind;
85 15328773 : uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
86 15328773 : if (clasp->flags & JSCLASS_HAS_PRIVATE)
87 2506557 : nslots++;
88 15328773 : return GetGCObjectKind(nslots);
89 : }
90 :
91 : /* As for GetGCObjectKind, but for dense array allocation. */
92 : static inline AllocKind
93 2556147 : 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 2556147 : if (numSlots > JSObject::NELEMENTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT)
105 103675 : return FINALIZE_OBJECT2;
106 2452472 : return slotsToThingKind[numSlots + 2];
107 : }
108 :
109 : static inline AllocKind
110 2604820 : GetGCObjectFixedSlotsKind(size_t numFixedSlots)
111 : {
112 : extern AllocKind slotsToThingKind[];
113 :
114 2604820 : JS_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
115 2604820 : return slotsToThingKind[numFixedSlots];
116 : }
117 :
118 : static inline bool
119 53401109 : IsBackgroundAllocKind(AllocKind kind)
120 : {
121 53401109 : JS_ASSERT(kind <= FINALIZE_LAST);
122 53401109 : return kind <= FINALIZE_OBJECT_LAST && kind % 2 == 1;
123 : }
124 :
125 : static inline AllocKind
126 15572244 : GetBackgroundAllocKind(AllocKind kind)
127 : {
128 15572244 : JS_ASSERT(!IsBackgroundAllocKind(kind));
129 15572244 : 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 22 : TryIncrementAllocKind(AllocKind *kindp)
138 : {
139 22 : size_t next = size_t(*kindp) + 2;
140 22 : if (next >= size_t(FINALIZE_OBJECT_LIMIT))
141 0 : return false;
142 22 : *kindp = AllocKind(next);
143 22 : return true;
144 : }
145 :
146 : /* Get the number of fixed slots and initial capacity associated with a kind. */
147 : static inline size_t
148 38296704 : GetGCKindSlots(AllocKind thingKind)
149 : {
150 : /* Using a switch in hopes that thingKind will usually be a compile-time constant. */
151 38296704 : switch (thingKind) {
152 : case FINALIZE_OBJECT0:
153 : case FINALIZE_OBJECT0_BACKGROUND:
154 2000989 : return 0;
155 : case FINALIZE_OBJECT2:
156 : case FINALIZE_OBJECT2_BACKGROUND:
157 19276938 : return 2;
158 : case FINALIZE_OBJECT4:
159 : case FINALIZE_OBJECT4_BACKGROUND:
160 11604589 : return 4;
161 : case FINALIZE_OBJECT8:
162 : case FINALIZE_OBJECT8_BACKGROUND:
163 2710034 : return 8;
164 : case FINALIZE_OBJECT12:
165 : case FINALIZE_OBJECT12_BACKGROUND:
166 1993284 : return 12;
167 : case FINALIZE_OBJECT16:
168 : case FINALIZE_OBJECT16_BACKGROUND:
169 710870 : 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 28802323 : GetGCKindSlots(AllocKind thingKind, Class *clasp)
178 : {
179 28802323 : size_t nslots = GetGCKindSlots(thingKind);
180 :
181 : /* An object's private data uses the space taken by its last fixed slot. */
182 28802323 : if (clasp->flags & JSCLASS_HAS_PRIVATE) {
183 7912228 : JS_ASSERT(nslots > 0);
184 7912228 : 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 28802323 : if (clasp == &FunctionClass)
192 15998603 : nslots = 0;
193 :
194 28802323 : return nslots;
195 : }
196 :
197 : static inline void
198 21115 : 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 21115 : 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 21115 : if (rt->gcZeal() == js::gc::ZealPokeValue)
214 0 : rt->gcNextScheduled = 1;
215 : #endif
216 21115 : }
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 122031 : ForEachArenaAndCell(JSCompartment *compartment, AllocKind thingKind,
225 : ArenaOp arenaOp, CellOp cellOp)
226 : {
227 122031 : size_t thingSize = Arena::thingSize(thingKind);
228 122031 : ArenaHeader *aheader = compartment->arenas.getFirstArena(thingKind);
229 :
230 203772 : for (; aheader; aheader = aheader->next) {
231 81741 : Arena *arena = aheader->getArena();
232 81741 : arenaOp(arena);
233 81741 : FreeSpan firstSpan(aheader->getFirstFreeSpan());
234 81741 : const FreeSpan *span = &firstSpan;
235 :
236 3163650 : for (uintptr_t thing = arena->thingsStart(thingKind); ; thing += thingSize) {
237 3163650 : JS_ASSERT(thing <= arena->thingsEnd());
238 3163650 : if (thing == span->first) {
239 246176 : if (!span->hasNext())
240 : break;
241 164435 : thing = span->last;
242 164435 : span = span->nextSpan();
243 : } else {
244 2917474 : Cell *t = reinterpret_cast<Cell *>(thing);
245 2917474 : cellOp(t);
246 : }
247 : }
248 : }
249 122031 : }
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 356711 : CellIterImpl() {
263 356711 : }
264 :
265 356711 : void initSpan(JSCompartment *comp, AllocKind kind) {
266 356711 : JS_ASSERT(comp->arenas.isSynchronizedFreeList(kind));
267 356711 : firstThingOffset = Arena::firstThingOffset(kind);
268 356711 : thingSize = Arena::thingSize(kind);
269 356711 : firstSpan.initAsEmpty();
270 356711 : span = &firstSpan;
271 356711 : thing = span->first;
272 356711 : }
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 356711 : void init(JSCompartment *comp, AllocKind kind) {
282 356711 : initSpan(comp, kind);
283 356711 : aheader = comp->arenas.getFirstArena(kind);
284 356711 : next();
285 356711 : }
286 :
287 : public:
288 58241458 : bool done() const {
289 58241458 : return !cell;
290 : }
291 :
292 28945569 : template<typename T> T *get() const {
293 28945569 : JS_ASSERT(!done());
294 28945569 : return static_cast<T *>(cell);
295 : }
296 :
297 0 : Cell *getCell() const {
298 0 : JS_ASSERT(!done());
299 0 : return cell;
300 : }
301 :
302 30682968 : void next() {
303 1387079 : for (;;) {
304 30682968 : if (thing != span->first)
305 28349870 : break;
306 2333098 : if (JS_LIKELY(span->hasNext())) {
307 589308 : thing = span->last + thingSize;
308 589308 : span = span->nextSpan();
309 589308 : break;
310 : }
311 1743790 : if (!aheader) {
312 356711 : cell = NULL;
313 356711 : return;
314 : }
315 1387079 : firstSpan = aheader->getFirstFreeSpan();
316 1387079 : span = &firstSpan;
317 1387079 : thing = aheader->arenaAddress() | firstThingOffset;
318 1387079 : aheader = aheader->next;
319 : }
320 28939178 : cell = reinterpret_cast<Cell *>(thing);
321 28939178 : thing += thingSize;
322 : }
323 : };
324 :
325 : class CellIterUnderGC : public CellIterImpl
326 : {
327 : public:
328 290010 : CellIterUnderGC(JSCompartment *comp, AllocKind kind) {
329 290010 : JS_ASSERT(comp->rt->gcRunning);
330 290010 : init(comp, kind);
331 290010 : }
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 66701 : CellIter(JSCompartment *comp, AllocKind kind)
353 : : lists(&comp->arenas),
354 66701 : 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 66701 : JS_ASSERT(!IsBackgroundAllocKind(kind));
363 66701 : if (lists->isSynchronizedFreeList(kind)) {
364 34752 : lists = NULL;
365 : } else {
366 31949 : JS_ASSERT(!comp->rt->gcRunning);
367 31949 : lists->copyFreeListToArena(kind);
368 : }
369 : #ifdef DEBUG
370 66701 : counter = &comp->rt->noGCOrAllocationCheck;
371 66701 : ++*counter;
372 : #endif
373 66701 : init(comp, kind);
374 66701 : }
375 :
376 66701 : ~CellIter() {
377 : #ifdef DEBUG
378 66701 : JS_ASSERT(*counter > 0);
379 66701 : --*counter;
380 : #endif
381 66701 : if (lists)
382 31949 : lists->clearFreeListInArena(kind);
383 66701 : }
384 : };
385 :
386 : /* Signatures for ArenaOp and CellOp above. */
387 :
388 80657 : 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 241518966 : NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
401 : {
402 241518966 : JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
403 : #ifdef JS_THREADSAFE
404 241518966 : JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
405 : kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
406 : #endif
407 241518966 : JS_ASSERT(!cx->runtime->gcRunning);
408 241518966 : JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
409 :
410 : /* For testing out of memory conditions */
411 241518966 : JS_OOM_POSSIBLY_FAIL();
412 :
413 : #ifdef JS_GC_ZEAL
414 241518966 : if (cx->runtime->needZealousGC())
415 9033 : js::gc::RunDebugGC(cx);
416 : #endif
417 :
418 241518966 : js::gc::MaybeCheckStackRoots(cx);
419 :
420 241518966 : JSCompartment *comp = cx->compartment;
421 241518966 : void *t = comp->arenas.allocateFromFreeList(kind, thingSize);
422 241518966 : if (!t)
423 2340684 : t = js::gc::ArenaLists::refillFreeList(cx, kind);
424 :
425 241518966 : JS_ASSERT_IF(t && comp->needsBarrier(),
426 : static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
427 241518966 : 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 28661541 : TryNewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
434 : {
435 28661541 : JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
436 : #ifdef JS_THREADSAFE
437 28661541 : JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
438 : kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
439 : #endif
440 28661541 : JS_ASSERT(!cx->runtime->gcRunning);
441 28661541 : JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
442 :
443 : #ifdef JS_GC_ZEAL
444 28661541 : if (cx->runtime->needZealousGC())
445 1505 : return NULL;
446 : #endif
447 :
448 28660036 : void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize);
449 28660036 : JS_ASSERT_IF(t && cx->compartment->needsBarrier(),
450 : static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
451 28660036 : return static_cast<T *>(t);
452 : }
453 :
454 : } /* namespace gc */
455 : } /* namespace js */
456 :
457 : inline JSObject *
458 11936154 : js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
459 : {
460 11936154 : JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
461 11936154 : return js::gc::NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
462 : }
463 :
464 : inline JSObject *
465 28661541 : js_TryNewGCObject(JSContext *cx, js::gc::AllocKind kind)
466 : {
467 28661541 : JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
468 28661541 : return js::gc::TryNewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
469 : }
470 :
471 : inline JSString *
472 128894817 : js_NewGCString(JSContext *cx)
473 : {
474 128894817 : return js::gc::NewGCThing<JSString>(cx, js::gc::FINALIZE_STRING, sizeof(JSString));
475 : }
476 :
477 : inline JSShortString *
478 52755193 : js_NewGCShortString(JSContext *cx)
479 : {
480 52755193 : return js::gc::NewGCThing<JSShortString>(cx, js::gc::FINALIZE_SHORT_STRING, sizeof(JSShortString));
481 : }
482 :
483 : inline JSExternalString *
484 971902 : js_NewGCExternalString(JSContext *cx)
485 : {
486 : return js::gc::NewGCThing<JSExternalString>(cx, js::gc::FINALIZE_EXTERNAL_STRING,
487 971902 : sizeof(JSExternalString));
488 : }
489 :
490 : inline JSScript *
491 1322523 : js_NewGCScript(JSContext *cx)
492 : {
493 1322523 : return js::gc::NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
494 : }
495 :
496 : inline js::Shape *
497 32691732 : js_NewGCShape(JSContext *cx)
498 : {
499 32691732 : return js::gc::NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
500 : }
501 :
502 : inline js::BaseShape *
503 7547759 : js_NewGCBaseShape(JSContext *cx)
504 : {
505 7547759 : 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___ */
|