1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16 * The Original Code is SpiderMonkey code.
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.
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.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef jsgcinlines_h___
41 #define jsgcinlines_h___
45 #include "jscompartment.h"
50 #include "js/TemplateLib.h"
59 GetGCThingTraceKind(const void *thing
)
62 const Cell
*cell
= reinterpret_cast<const Cell
*>(thing
);
63 return MapAllocToTraceKind(cell
->getAllocKind());
66 /* Capacity for slotsToThingKind */
67 const size_t SLOTS_TO_THING_KIND_LIMIT
= 17;
69 /* Get the best kind to use when making an object with the given slot count. */
70 static inline AllocKind
71 GetGCObjectKind(size_t numSlots
)
73 extern AllocKind slotsToThingKind
[];
75 if (numSlots
>= SLOTS_TO_THING_KIND_LIMIT
)
76 return FINALIZE_OBJECT16
;
77 return slotsToThingKind
[numSlots
];
80 static inline AllocKind
81 GetGCObjectKind(Class
*clasp
)
83 if (clasp
== &FunctionClass
)
84 return JSFunction::FinalizeKind
;
85 uint32_t nslots
= JSCLASS_RESERVED_SLOTS(clasp
);
86 if (clasp
->flags
& JSCLASS_HAS_PRIVATE
)
88 return GetGCObjectKind(nslots
);
91 /* As for GetGCObjectKind, but for dense array allocation. */
92 static inline AllocKind
93 GetGCArrayKind(size_t numSlots
)
95 extern AllocKind slotsToThingKind
[];
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
103 JS_STATIC_ASSERT(ObjectElements::VALUES_PER_HEADER
== 2);
104 if (numSlots
> JSObject::NELEMENTS_LIMIT
|| numSlots
+ 2 >= SLOTS_TO_THING_KIND_LIMIT
)
105 return FINALIZE_OBJECT2
;
106 return slotsToThingKind
[numSlots
+ 2];
109 static inline AllocKind
110 GetGCObjectFixedSlotsKind(size_t numFixedSlots
)
112 extern AllocKind slotsToThingKind
[];
114 JS_ASSERT(numFixedSlots
< SLOTS_TO_THING_KIND_LIMIT
);
115 return slotsToThingKind
[numFixedSlots
];
119 IsBackgroundAllocKind(AllocKind kind
)
121 JS_ASSERT(kind
<= FINALIZE_LAST
);
122 return kind
<= FINALIZE_OBJECT_LAST
&& kind
% 2 == 1;
125 static inline AllocKind
126 GetBackgroundAllocKind(AllocKind kind
)
128 JS_ASSERT(!IsBackgroundAllocKind(kind
));
129 return (AllocKind
) (kind
+ 1);
133 * Try to get the next larger size for an object, keeping BACKGROUND
137 TryIncrementAllocKind(AllocKind
*kindp
)
139 size_t next
= size_t(*kindp
) + 2;
140 if (next
>= size_t(FINALIZE_OBJECT_LIMIT
))
142 *kindp
= AllocKind(next
);
146 /* Get the number of fixed slots and initial capacity associated with a kind. */
148 GetGCKindSlots(AllocKind thingKind
)
150 /* Using a switch in hopes that thingKind will usually be a compile-time constant. */
152 case FINALIZE_OBJECT0
:
153 case FINALIZE_OBJECT0_BACKGROUND
:
155 case FINALIZE_OBJECT2
:
156 case FINALIZE_OBJECT2_BACKGROUND
:
158 case FINALIZE_OBJECT4
:
159 case FINALIZE_OBJECT4_BACKGROUND
:
161 case FINALIZE_OBJECT8
:
162 case FINALIZE_OBJECT8_BACKGROUND
:
164 case FINALIZE_OBJECT12
:
165 case FINALIZE_OBJECT12_BACKGROUND
:
167 case FINALIZE_OBJECT16
:
168 case FINALIZE_OBJECT16_BACKGROUND
:
171 JS_NOT_REACHED("Bad object finalize kind");
177 GetGCKindSlots(AllocKind thingKind
, Class
*clasp
)
179 size_t nslots
= GetGCKindSlots(thingKind
);
181 /* An object's private data uses the space taken by its last fixed slot. */
182 if (clasp
->flags
& JSCLASS_HAS_PRIVATE
) {
183 JS_ASSERT(nslots
> 0);
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.
191 if (clasp
== &FunctionClass
)
198 GCPoke(JSRuntime
*rt
, Value oldval
)
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
208 rt
->gcPoke
= oldval
.isGCThing();
212 /* Schedule a GC to happen "soon" after a GC poke. */
213 if (rt
->gcZeal() == js::gc::ZealPokeValue
)
214 rt
->gcNextScheduled
= 1;
219 * Invoke ArenaOp and CellOp on every arena and cell in a compartment which
220 * have the specified thing kind.
222 template <class ArenaOp
, class CellOp
>
224 ForEachArenaAndCell(JSCompartment
*compartment
, AllocKind thingKind
,
225 ArenaOp arenaOp
, CellOp cellOp
)
227 size_t thingSize
= Arena::thingSize(thingKind
);
228 ArenaHeader
*aheader
= compartment
->arenas
.getFirstArena(thingKind
);
230 for (; aheader
; aheader
= aheader
->next
) {
231 Arena
*arena
= aheader
->getArena();
233 FreeSpan
firstSpan(aheader
->getFirstFreeSpan());
234 const FreeSpan
*span
= &firstSpan
;
236 for (uintptr_t thing
= arena
->thingsStart(thingKind
); ; thing
+= thingSize
) {
237 JS_ASSERT(thing
<= arena
->thingsEnd());
238 if (thing
== span
->first
) {
239 if (!span
->hasNext())
242 span
= span
->nextSpan();
244 Cell
*t
= reinterpret_cast<Cell
*>(thing
);
253 size_t firstThingOffset
;
255 ArenaHeader
*aheader
;
257 const FreeSpan
*span
;
265 void initSpan(JSCompartment
*comp
, AllocKind kind
) {
266 JS_ASSERT(comp
->arenas
.isSynchronizedFreeList(kind
));
267 firstThingOffset
= Arena::firstThingOffset(kind
);
268 thingSize
= Arena::thingSize(kind
);
269 firstSpan
.initAsEmpty();
274 void init(ArenaHeader
*singleAheader
) {
275 aheader
= singleAheader
;
276 initSpan(aheader
->compartment
, aheader
->getAllocKind());
281 void init(JSCompartment
*comp
, AllocKind kind
) {
282 initSpan(comp
, kind
);
283 aheader
= comp
->arenas
.getFirstArena(kind
);
292 template<typename T
> T
*get() const {
294 return static_cast<T
*>(cell
);
297 Cell
*getCell() const {
304 if (thing
!= span
->first
)
306 if (JS_LIKELY(span
->hasNext())) {
307 thing
= span
->last
+ thingSize
;
308 span
= span
->nextSpan();
315 firstSpan
= aheader
->getFirstFreeSpan();
317 thing
= aheader
->arenaAddress() | firstThingOffset
;
318 aheader
= aheader
->next
;
320 cell
= reinterpret_cast<Cell
*>(thing
);
325 class CellIterUnderGC
: public CellIterImpl
328 CellIterUnderGC(JSCompartment
*comp
, AllocKind kind
) {
329 JS_ASSERT(comp
->rt
->gcRunning
);
333 CellIterUnderGC(ArenaHeader
*aheader
) {
334 JS_ASSERT(aheader
->compartment
->rt
->gcRunning
);
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.
344 class CellIter
: public CellIterImpl
352 CellIter(JSCompartment
*comp
, AllocKind kind
)
353 : lists(&comp
->arenas
),
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.
362 JS_ASSERT(!IsBackgroundAllocKind(kind
));
363 if (lists
->isSynchronizedFreeList(kind
)) {
366 JS_ASSERT(!comp
->rt
->gcRunning
);
367 lists
->copyFreeListToArena(kind
);
370 counter
= &comp
->rt
->noGCOrAllocationCheck
;
378 JS_ASSERT(*counter
> 0);
382 lists
->clearFreeListInArena(kind
);
386 /* Signatures for ArenaOp and CellOp above. */
388 inline void EmptyArenaOp(Arena
*arena
) {}
389 inline void EmptyCellOp(Cell
*t
) {}
391 class GCCompartmentsIter
{
393 JSCompartment
**it
, **end
;
396 GCCompartmentsIter(JSRuntime
*rt
) {
397 JS_ASSERT(rt
->gcRunning
);
398 it
= rt
->compartments
.begin();
399 end
= rt
->compartments
.end();
400 if (!(*it
)->isCollecting())
404 bool done() const { return it
== end
; }
410 } while (it
!= end
&& !(*it
)->isCollecting());
413 JSCompartment
*get() const {
418 operator JSCompartment
*() const { return get(); }
419 JSCompartment
*operator->() const { return get(); }
423 * Allocates a new GC thing. After a successful allocation the caller must
424 * fully initialize the thing before calling any function that can potentially
425 * trigger GC. This will ensure that GC tracing never sees junk values stored
426 * in the partially initialized thing.
429 template <typename T
>
431 NewGCThing(JSContext
*cx
, js::gc::AllocKind kind
, size_t thingSize
)
433 JS_ASSERT(thingSize
== js::gc::Arena::thingSize(kind
));
435 JS_ASSERT_IF((cx
->compartment
== cx
->runtime
->atomsCompartment
),
436 kind
== js::gc::FINALIZE_STRING
|| kind
== js::gc::FINALIZE_SHORT_STRING
);
438 JS_ASSERT(!cx
->runtime
->gcRunning
);
439 JS_ASSERT(!cx
->runtime
->noGCOrAllocationCheck
);
441 /* For testing out of memory conditions */
442 JS_OOM_POSSIBLY_FAIL_REPORT(cx
);
445 if (cx
->runtime
->needZealousGC())
446 js::gc::RunDebugGC(cx
);
449 MaybeCheckStackRoots(cx
);
451 JSCompartment
*comp
= cx
->compartment
;
452 void *t
= comp
->arenas
.allocateFromFreeList(kind
, thingSize
);
454 t
= js::gc::ArenaLists::refillFreeList(cx
, kind
);
456 JS_ASSERT_IF(t
&& comp
->needsBarrier(),
457 static_cast<T
*>(t
)->arenaHeader()->allocatedDuringIncremental
);
458 return static_cast<T
*>(t
);
461 /* Alternate form which allocates a GC thing if doing so cannot trigger a GC. */
462 template <typename T
>
464 TryNewGCThing(JSContext
*cx
, js::gc::AllocKind kind
, size_t thingSize
)
466 JS_ASSERT(thingSize
== js::gc::Arena::thingSize(kind
));
468 JS_ASSERT_IF((cx
->compartment
== cx
->runtime
->atomsCompartment
),
469 kind
== js::gc::FINALIZE_STRING
|| kind
== js::gc::FINALIZE_SHORT_STRING
);
471 JS_ASSERT(!cx
->runtime
->gcRunning
);
472 JS_ASSERT(!cx
->runtime
->noGCOrAllocationCheck
);
475 if (cx
->runtime
->needZealousGC())
479 void *t
= cx
->compartment
->arenas
.allocateFromFreeList(kind
, thingSize
);
480 JS_ASSERT_IF(t
&& cx
->compartment
->needsBarrier(),
481 static_cast<T
*>(t
)->arenaHeader()->allocatedDuringIncremental
);
482 return static_cast<T
*>(t
);
489 js_NewGCObject(JSContext
*cx
, js::gc::AllocKind kind
)
491 JS_ASSERT(kind
>= js::gc::FINALIZE_OBJECT0
&& kind
<= js::gc::FINALIZE_OBJECT_LAST
);
492 return js::gc::NewGCThing
<JSObject
>(cx
, kind
, js::gc::Arena::thingSize(kind
));
496 js_TryNewGCObject(JSContext
*cx
, js::gc::AllocKind kind
)
498 JS_ASSERT(kind
>= js::gc::FINALIZE_OBJECT0
&& kind
<= js::gc::FINALIZE_OBJECT_LAST
);
499 return js::gc::TryNewGCThing
<JSObject
>(cx
, kind
, js::gc::Arena::thingSize(kind
));
503 js_NewGCString(JSContext
*cx
)
505 return js::gc::NewGCThing
<JSString
>(cx
, js::gc::FINALIZE_STRING
, sizeof(JSString
));
508 inline JSShortString
*
509 js_NewGCShortString(JSContext
*cx
)
511 return js::gc::NewGCThing
<JSShortString
>(cx
, js::gc::FINALIZE_SHORT_STRING
, sizeof(JSShortString
));
514 inline JSExternalString
*
515 js_NewGCExternalString(JSContext
*cx
)
517 return js::gc::NewGCThing
<JSExternalString
>(cx
, js::gc::FINALIZE_EXTERNAL_STRING
,
518 sizeof(JSExternalString
));
522 js_NewGCScript(JSContext
*cx
)
524 return js::gc::NewGCThing
<JSScript
>(cx
, js::gc::FINALIZE_SCRIPT
, sizeof(JSScript
));
528 js_NewGCShape(JSContext
*cx
)
530 return js::gc::NewGCThing
<js::Shape
>(cx
, js::gc::FINALIZE_SHAPE
, sizeof(js::Shape
));
533 inline js::BaseShape
*
534 js_NewGCBaseShape(JSContext
*cx
)
536 return js::gc::NewGCThing
<js::BaseShape
>(cx
, js::gc::FINALIZE_BASE_SHAPE
, sizeof(js::BaseShape
));
539 #if JS_HAS_XML_SUPPORT
541 js_NewGCXML(JSContext
*cx
);
544 #endif /* jsgcinlines_h___ */