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 Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * 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 ***** */
43 * JS Garbage Collector.
52 #include "jsgcchunk.h"
56 #include "jsversion.h"
60 #if !defined JS_DUMP_CONSERVATIVE_GC_ROOTS && defined DEBUG
61 # define JS_DUMP_CONSERVATIVE_GC_ROOTS 1
64 #if defined JS_GCMETER
65 const bool JS_WANT_GC_METER_PRINT
= true;
68 const bool JS_WANT_GC_METER_PRINT
= false;
74 * One past the maximum trace kind.
76 #define JSTRACE_LIMIT 3
78 const uintN JS_EXTERNAL_STRING_LIMIT
= 8;
81 * Get the type of the external string or -1 if the string was not created
82 * with JS_NewExternalString.
85 js_GetExternalStringGCType(JSString
*str
);
87 extern JS_FRIEND_API(uint32
)
88 js_GetGCThingTraceKind(void *thing
);
91 * The sole purpose of the function is to preserve public API compatibility
92 * in JS_GetStringBytes which takes only single JSString* argument.
95 js_GetGCThingRuntime(void *thing
);
99 * Since we're forcing a GC from JS_GC anyway, don't bother wasting cycles
100 * loading oldval. XXX remove implied force, fix jsinterp.c's "second arg
103 #define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JS_TRUE)
105 #define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JSVAL_IS_GCTHING(oldval))
109 js_InitGC(JSRuntime
*rt
, uint32 maxbytes
);
112 js_FinishGC(JSRuntime
*rt
);
115 js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop
,
116 JSStringFinalizeOp newop
);
119 js_AddRoot(JSContext
*cx
, js::Value
*vp
, const char *name
);
122 js_AddGCThingRoot(JSContext
*cx
, void **rp
, const char *name
);
126 js_DumpNamedRoots(JSRuntime
*rt
,
127 void (*dump
)(const char *name
, void *rp
, JSGCRootType type
, void *data
),
132 js_MapGCRoots(JSRuntime
*rt
, JSGCRootMapFun map
, void *data
);
134 /* Table of pointers with count valid members. */
135 typedef struct JSPtrTable
{
141 js_RegisterCloseableIterator(JSContext
*cx
, JSObject
*obj
);
145 js_ReserveObjects(JSContext
*cx
, size_t nobjects
);
149 js_LockGCThingRT(JSRuntime
*rt
, void *thing
);
152 js_UnlockGCThingRT(JSRuntime
*rt
, void *thing
);
154 extern JS_FRIEND_API(bool)
155 js_IsAboutToBeFinalized(void *thing
);
157 extern JS_FRIEND_API(bool)
158 js_GCThingIsMarked(void *thing
, uint32 color
);
161 * Macro to test if a traversal is the marking phase of GC to avoid exposing
162 * ScriptFilenameEntry to traversal implementations.
164 #define IS_GC_MARKING_TRACER(trc) ((trc)->callback == NULL)
166 #if JS_HAS_XML_SUPPORT
167 # define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT)
169 # define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_STRING)
173 js_TraceStackFrame(JSTracer
*trc
, JSStackFrame
*fp
);
175 extern JS_REQUIRES_STACK
void
176 js_TraceRuntime(JSTracer
*trc
);
178 extern JS_REQUIRES_STACK
JS_FRIEND_API(void)
179 js_TraceContext(JSTracer
*trc
, JSContext
*acx
);
182 * Schedule the GC call at a later safe point.
184 #ifndef JS_THREADSAFE
185 # define js_TriggerGC(cx, gcLocked) js_TriggerGC (cx)
189 js_TriggerGC(JSContext
*cx
, JSBool gcLocked
);
192 * Kinds of js_GC invocation.
194 typedef enum JSGCInvocationKind
{
195 /* Normal invocation. */
199 * Called from js_DestroyContext for last JSContext in a JSRuntime, when
200 * it is imperative that rt->gcPoke gets cleared early in js_GC.
205 * Flag bit telling js_GC that the caller has already acquired rt->gcLock.
208 } JSGCInvocationKind
;
211 js_GC(JSContext
*cx
, JSGCInvocationKind gckind
);
215 * This is a helper for code at can potentially run outside JS request to
216 * ensure that the GC is not running when the function returns.
218 * This function must be called with the GC lock held.
221 js_WaitForGC(JSRuntime
*rt
);
223 #else /* !JS_THREADSAFE */
225 # define js_WaitForGC(rt) ((void) 0)
230 * The kind of GC thing with a finalizer. The external strings follow the
231 * ordinary string to simplify js_GetExternalStringGCType.
233 enum JSFinalizeGCThingKind
{
236 #if JS_HAS_XML_SUPPORT
239 FINALIZE_SHORT_STRING
,
241 FINALIZE_EXTERNAL_STRING0
,
242 FINALIZE_EXTERNAL_STRING1
,
243 FINALIZE_EXTERNAL_STRING2
,
244 FINALIZE_EXTERNAL_STRING3
,
245 FINALIZE_EXTERNAL_STRING4
,
246 FINALIZE_EXTERNAL_STRING5
,
247 FINALIZE_EXTERNAL_STRING6
,
248 FINALIZE_EXTERNAL_STRING7
,
249 FINALIZE_EXTERNAL_STRING_LAST
= FINALIZE_EXTERNAL_STRING7
,
254 IsFinalizableStringKind(unsigned thingKind
)
256 return unsigned(FINALIZE_SHORT_STRING
) <= thingKind
&&
257 thingKind
<= unsigned(FINALIZE_EXTERNAL_STRING_LAST
);
261 * Allocates a new GC thing. After a successful allocation the caller must
262 * fully initialize the thing before calling any function that can potentially
263 * trigger GC. This will ensure that GC tracing never sees junk values stored
264 * in the partially initialized thing.
267 js_NewFinalizableGCThing(JSContext
*cx
, unsigned thingKind
);
269 static inline JSObject
*
270 js_NewGCObject(JSContext
*cx
)
272 return (JSObject
*) js_NewFinalizableGCThing(cx
, FINALIZE_OBJECT
);
275 static inline JSString
*
276 js_NewGCString(JSContext
*cx
)
278 return (JSString
*) js_NewFinalizableGCThing(cx
, FINALIZE_STRING
);
281 struct JSShortString
;
283 static inline JSShortString
*
284 js_NewGCShortString(JSContext
*cx
)
286 return (JSShortString
*) js_NewFinalizableGCThing(cx
, FINALIZE_SHORT_STRING
);
289 static inline JSString
*
290 js_NewGCExternalString(JSContext
*cx
, uintN type
)
292 JS_ASSERT(type
< JS_EXTERNAL_STRING_LIMIT
);
293 type
+= FINALIZE_EXTERNAL_STRING0
;
294 return (JSString
*) js_NewFinalizableGCThing(cx
, type
);
297 static inline JSFunction
*
298 js_NewGCFunction(JSContext
*cx
)
300 JSFunction
* obj
= (JSFunction
*)js_NewFinalizableGCThing(cx
, FINALIZE_FUNCTION
);
304 memset((uint8
*) obj
+ sizeof(JSObject
), JS_FREE_PATTERN
,
305 sizeof(JSFunction
) - sizeof(JSObject
));
312 #if JS_HAS_XML_SUPPORT
313 static inline JSXML
*
314 js_NewGCXML(JSContext
*cx
)
316 return (JSXML
*) js_NewFinalizableGCThing(cx
, FINALIZE_XML
);
322 struct JSGCArenaList
{
323 JSGCArena
*head
; /* list start */
324 JSGCArena
*cursor
; /* arena with free things */
325 uint32 thingKind
; /* one of JSFinalizeGCThingKind */
326 uint32 thingSize
; /* size of things to allocate on this list
330 struct JSGCFreeLists
{
331 JSGCThing
*finalizables
[FINALIZE_LIMIT
];
334 void moveTo(JSGCFreeLists
* another
);
337 bool isEmpty() const {
338 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(finalizables
); ++i
) {
348 js_DestroyScriptsToGC(JSContext
*cx
, JSThreadData
*data
);
351 /* Most recently created things by type, members of the GC's root set. */
352 void *finalizableNewborns
[FINALIZE_LIMIT
];
354 /* Atom root for the last-looked-up atom on this context. */
357 /* Root for the result of the most recent js_InternalInvoke call. */
358 void *lastInternalResult
;
360 void mark(JSTracer
*trc
);
363 #define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots)))
370 * During the finalization we do not free immediately. Rather we add the
371 * corresponding pointers to a buffer which we later release on the
374 * The buffer is implemented as a vector of 64K arrays of pointers, not as a
375 * simple vector, to avoid realloc calls during the vector growth and to not
376 * bloat the binary size of the inlined freeLater method. Any OOM during
377 * buffer growth results in the pointer being freed immediately.
379 class BackgroundSweepTask
: public JSBackgroundTask
{
380 static const size_t FREE_ARRAY_SIZE
= size_t(1) << 16;
381 static const size_t FREE_ARRAY_LENGTH
= FREE_ARRAY_SIZE
/ sizeof(void *);
383 Vector
<void **, 16, js::SystemAllocPolicy
> freeVector
;
385 void **freeCursorEnd
;
388 replenishAndFreeLater(void *ptr
);
390 static void freeElementsAndArray(void **array
, void **end
) {
391 JS_ASSERT(array
<= end
);
392 for (void **p
= array
; p
!= end
; ++p
)
398 BackgroundSweepTask()
399 : freeCursor(NULL
), freeCursorEnd(NULL
) { }
401 void freeLater(void* ptr
) {
402 if (freeCursor
!= freeCursorEnd
)
405 replenishAndFreeLater(ptr
);
411 #endif /* JS_THREADSAFE */
416 struct GCChunkHasher
{
417 typedef jsuword Lookup
;
420 * Strip zeros for better distribution after multiplying by the golden
423 static HashNumber
hash(jsuword chunk
) {
424 JS_ASSERT(!(chunk
& GC_CHUNK_MASK
));
425 return HashNumber(chunk
>> GC_CHUNK_SHIFT
);
428 static bool match(jsuword k
, jsuword l
) {
429 JS_ASSERT(!(k
& GC_CHUNK_MASK
));
430 JS_ASSERT(!(l
& GC_CHUNK_MASK
));
435 typedef HashSet
<jsuword
, GCChunkHasher
, SystemAllocPolicy
> GCChunkSet
;
436 typedef Vector
<GCChunkInfo
*, 32, SystemAllocPolicy
> GCChunkInfoVector
;
438 struct ConservativeGCThreadData
{
441 * The GC scans conservatively between JSThreadData::nativeStackBase and
442 * nativeStackTop unless the latter is NULL.
444 jsuword
*nativeStackTop
;
448 jsuword words
[JS_HOWMANY(sizeof(jmp_buf), sizeof(jsuword
))];
453 JS_NEVER_INLINE
JS_FRIEND_API(void) enable(bool knownStackBoundary
= false);
454 JS_FRIEND_API(void) disable();
455 bool isEnabled() const { return enableCount
> 0; }
459 * The conservative GC test for a word shows that it is either a valid GC
460 * thing or is not for one of the following reasons.
462 enum ConservativeGCTest
{
464 CGCT_LOWBITSET
, /* excluded because one of the low bits was set */
465 CGCT_NOTARENA
, /* not within arena range in a chunk */
466 CGCT_NOTCHUNK
, /* not within a valid chunk */
467 CGCT_FREEARENA
, /* within arena containing only free things */
468 CGCT_WRONGTAG
, /* tagged pointer but wrong type */
469 CGCT_NOTLIVE
, /* gcthing is not allocated */
473 struct ConservativeGCStats
{
474 uint32 counter
[CGCT_END
]; /* ConservativeGCTest classification
477 void add(const ConservativeGCStats
&another
) {
478 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(counter
); ++i
)
479 counter
[i
] += another
.counter
[i
];
485 struct GCMarker
: public JSTracer
{
487 /* The color is only applied to objects, functions and xml. */
490 /* See comments before delayMarkingChildren is jsgc.cpp. */
491 JSGCArena
*unmarkedArenaStackTop
;
493 size_t markLaterCount
;
497 #if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
498 ConservativeGCStats conservativeStats
;
501 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
502 struct ConservativeRoot
{ void *thing
; uint32 traceKind
; };
503 Vector
<ConservativeRoot
, 0, SystemAllocPolicy
> conservativeRoots
;
504 const char *conservativeDumpFileName
;
506 void dumpConservativeRoots();
509 js::Vector
<JSObject
*, 0, js::SystemAllocPolicy
> arraysToSlowify
;
512 explicit GCMarker(JSContext
*cx
);
515 uint32
getMarkColor() const {
519 void setMarkColor(uint32 newColor
) {
521 * We must process any delayed marking here, otherwise we confuse
524 markDelayedChildren();
528 void delayMarkingChildren(void *thing
);
530 JS_FRIEND_API(void) markDelayedChildren();
532 void slowifyArrays();
538 js_FinalizeStringRT(JSRuntime
*rt
, JSString
*str
);
542 struct JSGCArenaStats
{
543 uint32 alloc
; /* allocation attempts */
544 uint32 localalloc
; /* allocations from local lists */
545 uint32 retry
; /* allocation retries after running the GC */
546 uint32 fail
; /* allocation failures */
547 uint32 nthings
; /* live GC things */
548 uint32 maxthings
; /* maximum of live GC cells */
549 double totalthings
; /* live GC things the GC scanned so far */
550 uint32 narenas
; /* number of arena in list before the GC */
551 uint32 newarenas
; /* new arenas allocated before the last GC */
552 uint32 livearenas
; /* number of live arenas after the last GC */
553 uint32 maxarenas
; /* maximum of allocated arenas */
554 uint32 totalarenas
; /* total number of arenas with live things that
559 uint32 finalfail
; /* finalizer calls allocator failures */
560 uint32 lockborn
; /* things born locked */
561 uint32 lock
; /* valid lock calls */
562 uint32 unlock
; /* valid unlock calls */
563 uint32 depth
; /* mark tail recursion depth */
564 uint32 maxdepth
; /* maximum mark tail recursion depth */
565 uint32 cdepth
; /* mark recursion depth of C functions */
566 uint32 maxcdepth
; /* maximum mark recursion depth of C functions */
567 uint32 unmarked
; /* number of times marking of GC thing's children were
568 delayed due to a low C stack */
570 uint32 maxunmarked
;/* maximum number of things with children to mark
573 uint32 poke
; /* number of potentially useful GC calls */
574 uint32 afree
; /* thing arenas freed so far */
575 uint32 stackseg
; /* total extraordinary stack segments scanned */
576 uint32 segslots
; /* total stack segment value slots scanned */
577 uint32 nclose
; /* number of objects with close hooks */
578 uint32 maxnclose
; /* max number of objects with close hooks */
579 uint32 closelater
; /* number of close hooks scheduled to run */
580 uint32 maxcloselater
; /* max number of close hooks scheduled to run */
581 uint32 nallarenas
; /* number of all allocated arenas */
582 uint32 maxnallarenas
; /* maximum number of all allocated arenas */
583 uint32 nchunks
; /* number of allocated chunks */
584 uint32 maxnchunks
; /* maximum number of allocated chunks */
586 JSGCArenaStats arenaStats
[FINALIZE_LIMIT
];
588 js::ConservativeGCStats conservative
;
591 extern JS_FRIEND_API(void)
592 js_DumpGCStats(JSRuntime
*rt
, FILE *fp
);
594 #endif /* JS_GCMETER */
597 * This function is defined in jsdbgapi.cpp but is declared here to avoid
598 * polluting jsdbgapi.h, a public API header, with internal functions.
601 js_MarkTraps(JSTracer
*trc
);
606 * Set object's prototype while checking that doing so would not create
607 * a cycle in the proto chain. The cycle check and proto change are done
608 * only when all other requests are finished or suspended to ensure exclusive
609 * access to the chain. If there is a cycle, return false without reporting
610 * an error. Otherwise, set the proto and return true.
613 SetProtoCheckingForCycles(JSContext
*cx
, JSObject
*obj
, JSObject
*proto
);
615 /* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
617 Mark(JSTracer
*trc
, void *thing
, uint32 kind
);
620 Mark(JSTracer
*trc
, void *thing
, uint32 kind
, const char *name
)
623 JS_SET_TRACING_NAME(trc
, name
);
624 Mark(trc
, thing
, kind
);
628 MarkString(JSTracer
*trc
, JSString
*str
)
631 Mark(trc
, str
, JSTRACE_STRING
);
635 MarkString(JSTracer
*trc
, JSString
*str
, const char *name
)
638 JS_SET_TRACING_NAME(trc
, name
);
639 Mark(trc
, str
, JSTRACE_STRING
);
643 MarkAtomRange(JSTracer
*trc
, size_t len
, JSAtom
**vec
, const char *name
)
645 for (uint32 i
= 0; i
< len
; i
++) {
646 if (JSAtom
*atom
= vec
[i
]) {
647 JS_SET_TRACING_INDEX(trc
, name
, i
);
648 Mark(trc
, ATOM_TO_STRING(atom
), JSTRACE_STRING
);
654 MarkObject(JSTracer
*trc
, JSObject
*obj
, const char *name
)
657 JS_SET_TRACING_NAME(trc
, name
);
658 Mark(trc
, obj
, JSTRACE_OBJECT
);
662 MarkObjectRange(JSTracer
*trc
, size_t len
, JSObject
**vec
, const char *name
)
664 for (uint32 i
= 0; i
< len
; i
++) {
665 if (JSObject
*obj
= vec
[i
]) {
666 JS_SET_TRACING_INDEX(trc
, name
, i
);
667 Mark(trc
, obj
, JSTRACE_OBJECT
);
672 /* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
674 MarkValueRaw(JSTracer
*trc
, const js::Value
&v
)
677 return Mark(trc
, v
.asGCThing(), v
.gcKind());
681 MarkValue(JSTracer
*trc
, const js::Value
&v
, const char *name
)
683 JS_SET_TRACING_NAME(trc
, name
);
684 MarkValueRaw(trc
, v
);
688 MarkValueRange(JSTracer
*trc
, Value
*beg
, Value
*end
, const char *name
)
690 for (Value
*vp
= beg
; vp
< end
; ++vp
) {
691 JS_SET_TRACING_INDEX(trc
, name
, vp
- beg
);
692 MarkValueRaw(trc
, *vp
);
697 MarkValueRange(JSTracer
*trc
, size_t len
, Value
*vec
, const char *name
)
699 MarkValueRange(trc
, vec
, vec
+ len
, name
);
703 MarkId(JSTracer
*trc
, jsid id
)
705 if (JSID_IS_STRING(id
))
706 Mark(trc
, JSID_TO_STRING(id
), JSTRACE_STRING
);
707 else if (JS_UNLIKELY(JSID_IS_OBJECT(id
)))
708 Mark(trc
, JSID_TO_OBJECT(id
), JSTRACE_OBJECT
);
712 MarkId(JSTracer
*trc
, jsid id
, const char *name
)
714 JS_SET_TRACING_NAME(trc
, name
);
719 MarkIdRange(JSTracer
*trc
, jsid
*beg
, jsid
*end
, const char *name
)
721 for (jsid
*idp
= beg
; idp
!= end
; ++idp
) {
722 JS_SET_TRACING_INDEX(trc
, name
, (idp
- beg
));
728 MarkIdRange(JSTracer
*trc
, size_t len
, jsid
*vec
, const char *name
)
730 MarkIdRange(trc
, vec
, vec
+ len
, name
);
733 /* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
735 MarkGCThing(JSTracer
*trc
, void *thing
);
738 MarkGCThing(JSTracer
*trc
, void *thing
, const char *name
)
740 JS_SET_TRACING_NAME(trc
, name
);
741 MarkGCThing(trc
, thing
);
745 MarkGCThing(JSTracer
*trc
, void *thing
, const char *name
, size_t index
)
747 JS_SET_TRACING_INDEX(trc
, name
, index
);
748 MarkGCThing(trc
, thing
);
752 NewCompartment(JSContext
*cx
, JSPrincipals
*principals
);
756 #endif /* jsgc_h___ */