bug 579100 - various GC cleanups. r=anygregor

This commit is contained in:
Igor Bukanov 2010-07-26 20:44:04 +02:00
parent 4c5fd024ab
commit 248a67333b
6 changed files with 180 additions and 188 deletions

View File

@ -1012,11 +1012,9 @@ array_trace(JSTracer *trc, JSObject *obj)
MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems"); MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems");
} }
if (trc == trc->context->runtime->gcMarkingTracer && if (IS_GC_MARKING_TRACER(trc) && holes > MIN_SPARSE_INDEX && holes > capacity / 4 * 3) {
holes > MIN_SPARSE_INDEX &&
holes > capacity / 4 * 3) {
/* This might fail, in which case we don't slowify it. */ /* This might fail, in which case we don't slowify it. */
reinterpret_cast<JSGCTracer *>(trc)->arraysToSlowify.append(obj); static_cast<GCMarker *>(trc)->arraysToSlowify.append(obj);
} }
} }

View File

@ -1171,6 +1171,50 @@ typedef HashMap<Value, Value, WrapperHasher, SystemAllocPolicy> WrapperMap;
class AutoValueVector; class AutoValueVector;
class AutoIdVector; class AutoIdVector;
struct GCMarker : public JSTracer {
private:
/* The color is only applied to objects, functions and xml. */
uint32 color;
/* See comments before delayMarkingChildren is jsgc.cpp. */
JSGCArena *unmarkedArenaStackTop;
#ifdef DEBUG
size_t markLaterCount;
#endif
public:
js::Vector<JSObject *, 0, js::SystemAllocPolicy> arraysToSlowify;
public:
explicit GCMarker(JSContext *cx)
: color(0), unmarkedArenaStackTop(NULL)
{
JS_TRACER_INIT(this, cx, NULL);
#ifdef DEBUG
markLaterCount = 0;
#endif
}
uint32 getMarkColor() const {
return color;
}
void setMarkColor(uint32 newColor) {
/*
* We must process any delayed marking here, otherwise we confuse
* colors.
*/
markDelayedChildren();
color = newColor;
}
void delayMarkingChildren(void *thing);
JS_FRIEND_API(void) markDelayedChildren();
void slowifyArrays();
};
} /* namespace js */ } /* namespace js */
struct JSCompartment { struct JSCompartment {
@ -1197,11 +1241,6 @@ struct JSCompartment {
void sweep(JSContext *cx); void sweep(JSContext *cx);
}; };
struct JSGCTracer : public JSTracer {
uint32 color;
js::Vector<JSObject *, 0, js::SystemAllocPolicy> arraysToSlowify;
};
extern JS_FRIEND_API(void) extern JS_FRIEND_API(void)
js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked); js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked);
@ -1251,7 +1290,7 @@ struct JSRuntime {
size_t gcMaxMallocBytes; size_t gcMaxMallocBytes;
uint32 gcEmptyArenaPoolLifespan; uint32 gcEmptyArenaPoolLifespan;
uint32 gcNumber; uint32 gcNumber;
JSGCTracer *gcMarkingTracer; js::GCMarker *gcMarkingTracer;
uint32 gcTriggerFactor; uint32 gcTriggerFactor;
size_t gcTriggerBytes; size_t gcTriggerBytes;
volatile JSBool gcIsNeeded; volatile JSBool gcIsNeeded;
@ -1290,12 +1329,6 @@ struct JSRuntime {
*/ */
volatile ptrdiff_t gcMallocBytes; volatile ptrdiff_t gcMallocBytes;
/* See comments before DelayMarkingChildren is jsgc.cpp. */
JSGCArena *gcUnmarkedArenaStackTop;
#ifdef DEBUG
size_t gcMarkLaterCount;
#endif
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
JSBackgroundThread gcHelperThread; JSBackgroundThread gcHelperThread;
#endif #endif

View File

@ -240,12 +240,9 @@ JS_STATIC_ASSERT(sizeof(JSFunction) % GC_CELL_SIZE == 0);
JS_STATIC_ASSERT(sizeof(JSXML) % GC_CELL_SIZE == 0); JS_STATIC_ASSERT(sizeof(JSXML) % GC_CELL_SIZE == 0);
#endif #endif
JS_STATIC_ASSERT(GC_CELL_SIZE == sizeof(jsdouble));
const size_t DOUBLES_PER_ARENA = GC_CELLS_PER_ARENA;
struct JSGCArenaInfo { struct JSGCArenaInfo {
/* /*
* Allocation list for the arena or NULL if the arena holds double values. * Allocation list for the arena.
*/ */
JSGCArenaList *list; JSGCArenaList *list;
@ -571,9 +568,8 @@ GCArenaIndexToThing(JSGCArena *a, JSGCArenaInfo *ainfo, size_t index)
/* /*
* The private JSGCThing struct, which describes a JSRuntime.gcFreeList element. * The private JSGCThing struct, which describes a JSRuntime.gcFreeList element.
*/ */
union JSGCThing { struct JSGCThing {
JSGCThing *link; JSGCThing *link;
double asDouble;
}; };
static inline JSGCThing * static inline JSGCThing *
@ -883,25 +879,6 @@ js_IsAboutToBeFinalized(void *thing)
return !IsMarkedGCThing(thing); return !IsMarkedGCThing(thing);
} }
static void
MarkDelayedChildren(JSTracer *trc);
/* The color is only applied to objects, functions and xml. */
JS_FRIEND_API(uint32)
js_SetMarkColor(JSTracer *trc, uint32 color)
{
JSGCTracer *gctracer = trc->context->runtime->gcMarkingTracer;
if (trc != gctracer)
return color;
/* Must process any delayed tracing here, otherwise we confuse colors. */
MarkDelayedChildren(trc);
uint32 oldColor = gctracer->color;
gctracer->color = color;
return oldColor;
}
JS_FRIEND_API(bool) JS_FRIEND_API(bool)
js_GCThingIsMarked(void *thing, uint32 color) js_GCThingIsMarked(void *thing, uint32 color)
{ {
@ -1903,6 +1880,8 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
} }
} }
namespace js {
/* /*
* When the native stack is low, the GC does not call JS_TraceChildren to mark * When the native stack is low, the GC does not call JS_TraceChildren to mark
* the reachable "children" of the thing. Rather the thing is put aside and * the reachable "children" of the thing. Rather the thing is put aside and
@ -1912,8 +1891,8 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
* the normal case of sufficient native stack, the code uses two fields per * the normal case of sufficient native stack, the code uses two fields per
* arena stored in JSGCMarkingDelay. The first field, JSGCMarkingDelay::link, * arena stored in JSGCMarkingDelay. The first field, JSGCMarkingDelay::link,
* links all arenas with delayed things into a stack list with the pointer to * links all arenas with delayed things into a stack list with the pointer to
* stack top in JSRuntime::gcUnmarkedArenaStackTop. DelayMarkingChildren adds * stack top in JSRuntime::gcUnmarkedArenaStackTop. delayMarkingChildren adds
* arenas to the stack as necessary while MarkDelayedChildren pops the arenas * arenas to the stack as necessary while markDelayedChildren pops the arenas
* from the stack until it empties. * from the stack until it empties.
* *
* The second field, JSGCMarkingDelay::unmarkedChildren, is a bitmap that * The second field, JSGCMarkingDelay::unmarkedChildren, is a bitmap that
@ -1921,7 +1900,7 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
* bitmap is a single word. As such it does not pinpoint the delayed things * bitmap is a single word. As such it does not pinpoint the delayed things
* in the arena but rather tells the intervals containing * in the arena but rather tells the intervals containing
* ThingsPerUnmarkedBit(thingSize) things. Later the code in * ThingsPerUnmarkedBit(thingSize) things. Later the code in
* MarkDelayedChildren discovers such intervals and calls JS_TraceChildren on * markDelayedChildren discovers such intervals and calls JS_TraceChildren on
* any marked thing in the interval. This implies that JS_TraceChildren can be * any marked thing in the interval. This implies that JS_TraceChildren can be
* called many times for a single thing if the thing shares the same interval * called many times for a single thing if the thing shares the same interval
* with some delayed things. This should be fine as any GC graph * with some delayed things. This should be fine as any GC graph
@ -1943,11 +1922,12 @@ ThingsPerUnmarkedBit(unsigned thingSize)
return JS_HOWMANY(ThingsPerArena(thingSize), JS_BITS_PER_WORD); return JS_HOWMANY(ThingsPerArena(thingSize), JS_BITS_PER_WORD);
} }
static void void
DelayMarkingChildren(JSRuntime *rt, void *thing) GCMarker::delayMarkingChildren(void *thing)
{ {
JS_ASSERT(this == context->runtime->gcMarkingTracer);
JS_ASSERT(IsMarkedGCThing(thing)); JS_ASSERT(IsMarkedGCThing(thing));
METER(rt->gcStats.unmarked++); METER(context->runtime->gcStats.unmarked++);
JSGCArena *a = JSGCArena::fromGCThing(thing); JSGCArena *a = JSGCArena::fromGCThing(thing);
JSGCArenaInfo *ainfo = a->getInfo(); JSGCArenaInfo *ainfo = a->getInfo();
@ -1960,7 +1940,7 @@ DelayMarkingChildren(JSRuntime *rt, void *thing)
jsuword bit = jsuword(1) << unmarkedBitIndex; jsuword bit = jsuword(1) << unmarkedBitIndex;
if (markingDelay->unmarkedChildren != 0) { if (markingDelay->unmarkedChildren != 0) {
JS_ASSERT(rt->gcUnmarkedArenaStackTop); JS_ASSERT(unmarkedArenaStackTop);
if (markingDelay->unmarkedChildren & bit) { if (markingDelay->unmarkedChildren & bit) {
/* bit already covers things with children to mark later. */ /* bit already covers things with children to mark later. */
return; return;
@ -1977,58 +1957,53 @@ DelayMarkingChildren(JSRuntime *rt, void *thing)
* even when the stack contains one element, we make prevUnmarked * even when the stack contains one element, we make prevUnmarked
* for the arena at the bottom to point to itself. * for the arena at the bottom to point to itself.
* *
* See comments in MarkDelayedChildren. * See comments in markDelayedChildren.
*/ */
markingDelay->unmarkedChildren = bit; markingDelay->unmarkedChildren = bit;
if (!markingDelay->link) { if (!markingDelay->link) {
if (!rt->gcUnmarkedArenaStackTop) { if (!unmarkedArenaStackTop) {
/* Stack was empty, mark the arena as the bottom element. */ /* Stack was empty, mark the arena as the bottom element. */
markingDelay->link = a; markingDelay->link = a;
} else { } else {
JS_ASSERT(rt->gcUnmarkedArenaStackTop->getMarkingDelay()->link); JS_ASSERT(unmarkedArenaStackTop->getMarkingDelay()->link);
markingDelay->link = rt->gcUnmarkedArenaStackTop; markingDelay->link = unmarkedArenaStackTop;
} }
rt->gcUnmarkedArenaStackTop = a; unmarkedArenaStackTop = a;
} }
JS_ASSERT(rt->gcUnmarkedArenaStackTop); JS_ASSERT(unmarkedArenaStackTop);
} }
#ifdef DEBUG #ifdef DEBUG
rt->gcMarkLaterCount += ThingsPerUnmarkedBit(ainfo->list->thingSize); markLaterCount += ThingsPerUnmarkedBit(ainfo->list->thingSize);
METER_UPDATE_MAX(rt->gcStats.maxunmarked, rt->gcMarkLaterCount); METER_UPDATE_MAX(context->runtime->gcStats.maxunmarked, markLaterCount);
#endif #endif
} }
static void JS_FRIEND_API(void)
MarkDelayedChildren(JSTracer *trc) GCMarker::markDelayedChildren()
{ {
JSRuntime *rt; JS_ASSERT(this == context->runtime->gcMarkingTracer);
JSGCArena *a, *aprev;
unsigned thingSize, traceKind;
unsigned thingsPerUnmarkedBit;
unsigned unmarkedBitIndex, thingIndex, indexLimit, endIndex;
rt = trc->context->runtime; JSGCArena *a = unmarkedArenaStackTop;
a = rt->gcUnmarkedArenaStackTop;
if (!a) { if (!a) {
JS_ASSERT(rt->gcMarkLaterCount == 0); JS_ASSERT(markLaterCount == 0);
return; return;
} }
for (;;) { for (;;) {
/* /*
* The following assert verifies that the current arena belongs to the * The following assert verifies that the current arena belongs to the
* unmarked stack, since DelayMarkingChildren ensures that even for * unmarked stack, since delayMarkingChildren ensures that even for
* the stack's bottom, prevUnmarked != 0 but rather points to * the stack's bottom, prevUnmarked != 0 but rather points to
* itself. * itself.
*/ */
JSGCArenaInfo *ainfo = a->getInfo(); JSGCArenaInfo *ainfo = a->getInfo();
JSGCMarkingDelay *markingDelay = a->getMarkingDelay(); JSGCMarkingDelay *markingDelay = a->getMarkingDelay();
JS_ASSERT(markingDelay->link); JS_ASSERT(markingDelay->link);
JS_ASSERT(rt->gcUnmarkedArenaStackTop->getMarkingDelay()->link); JS_ASSERT(unmarkedArenaStackTop->getMarkingDelay()->link);
thingSize = ainfo->list->thingSize; unsigned thingSize = ainfo->list->thingSize;
traceKind = GetFinalizableArenaTraceKind(ainfo); unsigned traceKind = GetFinalizableArenaTraceKind(ainfo);
indexLimit = ThingsPerArena(thingSize); unsigned indexLimit = ThingsPerArena(thingSize);
thingsPerUnmarkedBit = ThingsPerUnmarkedBit(thingSize); unsigned thingsPerUnmarkedBit = ThingsPerUnmarkedBit(thingSize);
/* /*
* We cannot use do-while loop here as a->unmarkedChildren can be zero * We cannot use do-while loop here as a->unmarkedChildren can be zero
@ -2036,14 +2011,14 @@ MarkDelayedChildren(JSTracer *trc)
* comments after the loop. * comments after the loop.
*/ */
while (markingDelay->unmarkedChildren != 0) { while (markingDelay->unmarkedChildren != 0) {
unmarkedBitIndex = JS_FLOOR_LOG2W(markingDelay->unmarkedChildren); unsigned unmarkedBitIndex = JS_FLOOR_LOG2W(markingDelay->unmarkedChildren);
markingDelay->unmarkedChildren &= ~(jsuword(1) << unmarkedBitIndex); markingDelay->unmarkedChildren &= ~(jsuword(1) << unmarkedBitIndex);
#ifdef DEBUG #ifdef DEBUG
JS_ASSERT(rt->gcMarkLaterCount >= thingsPerUnmarkedBit); JS_ASSERT(markLaterCount >= thingsPerUnmarkedBit);
rt->gcMarkLaterCount -= thingsPerUnmarkedBit; markLaterCount -= thingsPerUnmarkedBit;
#endif #endif
thingIndex = unmarkedBitIndex * thingsPerUnmarkedBit; unsigned thingIndex = unmarkedBitIndex * thingsPerUnmarkedBit;
endIndex = thingIndex + thingsPerUnmarkedBit; unsigned endIndex = thingIndex + thingsPerUnmarkedBit;
/* /*
* endIndex can go beyond the last allocated thing as the real * endIndex can go beyond the last allocated thing as the real
@ -2056,7 +2031,7 @@ MarkDelayedChildren(JSTracer *trc)
do { do {
JS_ASSERT(thing < end); JS_ASSERT(thing < end);
if (IsMarkedGCThing(thing)) if (IsMarkedGCThing(thing))
JS_TraceChildren(trc, thing, traceKind); JS_TraceChildren(this, thing, traceKind);
thing += thingSize; thing += thingSize;
} while (thing != end); } while (thing != end);
} }
@ -2066,12 +2041,12 @@ MarkDelayedChildren(JSTracer *trc)
* pop it from the stack if the arena is the stack's top. * pop it from the stack if the arena is the stack's top.
* *
* When JS_TraceChildren from the above calls JS_CallTracer that in * When JS_TraceChildren from the above calls JS_CallTracer that in
* turn on low C stack calls DelayMarkingChildren and the latter * turn on low C stack calls delayMarkingChildren and the latter
* pushes new arenas to the unmarked stack, we have to skip popping * pushes new arenas to the unmarked stack, we have to skip popping
* of this arena until it becomes the top of the stack again. * of this arena until it becomes the top of the stack again.
*/ */
if (a == rt->gcUnmarkedArenaStackTop) { if (a == unmarkedArenaStackTop) {
aprev = markingDelay->link; JSGCArena *aprev = markingDelay->link;
markingDelay->link = NULL; markingDelay->link = NULL;
if (a == aprev) { if (a == aprev) {
/* /*
@ -2080,95 +2055,95 @@ MarkDelayedChildren(JSTracer *trc)
*/ */
break; break;
} }
rt->gcUnmarkedArenaStackTop = a = aprev; unmarkedArenaStackTop = a = aprev;
} else { } else {
a = rt->gcUnmarkedArenaStackTop; a = unmarkedArenaStackTop;
} }
} }
JS_ASSERT(rt->gcUnmarkedArenaStackTop); JS_ASSERT(unmarkedArenaStackTop);
JS_ASSERT(!rt->gcUnmarkedArenaStackTop->getMarkingDelay()->link); JS_ASSERT(!unmarkedArenaStackTop->getMarkingDelay()->link);
rt->gcUnmarkedArenaStackTop = NULL; unmarkedArenaStackTop = NULL;
JS_ASSERT(rt->gcMarkLaterCount == 0); JS_ASSERT(markLaterCount == 0);
} }
namespace js { void
GCMarker::slowifyArrays()
{
while (!arraysToSlowify.empty()) {
JSObject *obj = arraysToSlowify.back();
arraysToSlowify.popBack();
if (IsMarkedGCThing(obj))
obj->makeDenseArraySlow(context);
}
}
void void
Mark(JSTracer *trc, void *thing, uint32 kind) Mark(JSTracer *trc, void *thing, uint32 kind)
{ {
JSContext *cx;
JSRuntime *rt;
JS_ASSERT(thing); JS_ASSERT(thing);
JS_ASSERT(JS_IS_VALID_TRACE_KIND(kind)); JS_ASSERT(JS_IS_VALID_TRACE_KIND(kind));
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg); JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
JS_ASSERT_IF(!JSString::isStatic(thing), kind == GetFinalizableThingTraceKind(thing));
#ifdef DEBUG
if (IS_GC_MARKING_TRACER(trc)) {
JSRuntime *rt = trc->context->runtime;
JS_ASSERT(rt->gcMarkingTracer == trc);
JS_ASSERT(rt->gcRunning);
}
#endif
if (!IS_GC_MARKING_TRACER(trc)) { if (!IS_GC_MARKING_TRACER(trc)) {
trc->callback(trc, thing, kind); trc->callback(trc, thing, kind);
goto out;
}
cx = trc->context;
rt = cx->runtime;
JS_ASSERT(rt->gcMarkingTracer == trc);
JS_ASSERT(rt->gcRunning);
/*
* Optimize for string and double as their size is known and their tracing
* is not recursive.
*/
if (kind == JSTRACE_STRING) {
/*
* Iterate through all nodes and leaves in the rope if this is part of a
* rope; otherwise, we only iterate once: on the string itself.
*/
JSRopeNodeIterator iter((JSString *) thing);
JSString *str = iter.init();
do {
for (;;) {
if (JSString::isStatic(str))
break;
JS_ASSERT(kind == GetFinalizableThingTraceKind(str));
if (!MarkIfUnmarkedGCThing(str))
break;
if (!str->isDependent())
break;
str = str->dependentBase();
}
str = iter.next();
} while (str);
goto out;
/* NOTREACHED */
}
JS_ASSERT(kind == GetFinalizableThingTraceKind(thing));
if (!MarkIfUnmarkedGCThing(thing, reinterpret_cast<JSGCTracer *>(trc)->color))
goto out;
/*
* With JS_GC_ASSUME_LOW_C_STACK defined the mark phase of GC always
* uses the non-recursive code that otherwise would be called only on
* a low C stack condition.
*/
#ifdef JS_GC_ASSUME_LOW_C_STACK
# define RECURSION_TOO_DEEP() JS_TRUE
#else
int stackDummy;
# define RECURSION_TOO_DEEP() (!JS_CHECK_STACK_SIZE(cx, stackDummy))
#endif
if (RECURSION_TOO_DEEP()) {
DelayMarkingChildren(rt, thing);
} else { } else {
JS_TraceChildren(trc, thing, kind); GCMarker *gcmarker = static_cast<GCMarker *>(trc);
if (kind == JSTRACE_STRING) {
/*
* Optimize for string as their marking is not recursive.
*
* Iterate through all nodes and leaves in the rope if this is
* part of a rope; otherwise, we only iterate once: on the string
* itself.
*/
JSRopeNodeIterator iter((JSString *) thing);
JSString *str = iter.init();
do {
for (;;) {
if (JSString::isStatic(str))
break;
JS_ASSERT(kind == GetFinalizableThingTraceKind(str));
if (!MarkIfUnmarkedGCThing(str))
break;
if (!str->isDependent())
break;
str = str->dependentBase();
}
str = iter.next();
} while (str);
} else if (MarkIfUnmarkedGCThing(thing, gcmarker->getMarkColor())) {
/*
* With JS_GC_ASSUME_LOW_C_STACK defined the mark phase of GC
* always uses the non-recursive code that otherwise would be
* called only on a low C stack condition.
*/
#ifdef JS_GC_ASSUME_LOW_C_STACK
# define RECURSION_TOO_DEEP() true
#else
int stackDummy;
# define RECURSION_TOO_DEEP() (!JS_CHECK_STACK_SIZE(trc->context, stackDummy))
#endif
if (RECURSION_TOO_DEEP())
gcmarker->delayMarkingChildren(thing);
else
JS_TraceChildren(trc, thing, kind);
}
} }
out:
#ifdef DEBUG #ifdef DEBUG
trc->debugPrinter = NULL; trc->debugPrinter = NULL;
trc->debugPrintArg = NULL; trc->debugPrintArg = NULL;
#endif #endif
return; /* to avoid out: right_curl when DEBUG is not defined */
} }
void void
@ -2821,15 +2796,6 @@ struct GCTimer {
# define GCTIMER_END(last) ((void) 0) # define GCTIMER_END(last) ((void) 0)
#endif #endif
static inline bool
HasMarkedDoubles(JSGCArena *a)
{
JS_STATIC_ASSERT(GC_MARK_BITMAP_SIZE == 8 * sizeof(uint64));
uint64 *markBitmap = (uint64 *) a->getMarkBitmap();
return !!(markBitmap[0] | markBitmap[1] | markBitmap[2] | markBitmap[3] |
markBitmap[4] | markBitmap[5] | markBitmap[6] | markBitmap[7]);
}
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
namespace js { namespace js {
@ -2959,29 +2925,25 @@ GC(JSContext *cx GCTIMER_PARAM)
{ {
JSRuntime *rt = cx->runtime; JSRuntime *rt = cx->runtime;
rt->gcNumber++; rt->gcNumber++;
JS_ASSERT(!rt->gcUnmarkedArenaStackTop);
JS_ASSERT(rt->gcMarkLaterCount == 0);
/* /*
* Mark phase. * Mark phase.
*/ */
JSGCTracer trc; GCMarker gcmarker(cx);
JS_TRACER_INIT(&trc, cx, NULL); JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker));
trc.color = BLACK; JS_ASSERT(gcmarker.getMarkColor() == BLACK);
rt->gcMarkingTracer = &trc; rt->gcMarkingTracer = &gcmarker;
JS_ASSERT(IS_GC_MARKING_TRACER(&trc));
for (JSGCChunkInfo **i = rt->gcChunks.begin(); i != rt->gcChunks.end(); ++i) for (JSGCChunkInfo **i = rt->gcChunks.begin(); i != rt->gcChunks.end(); ++i)
(*i)->clearMarkBitmap(); (*i)->clearMarkBitmap();
js_TraceRuntime(&trc); js_TraceRuntime(&gcmarker);
js_MarkScriptFilenames(rt); js_MarkScriptFilenames(rt);
/* /*
* Mark children of things that caused too deep recursion during the above * Mark children of things that caused too deep recursion during the above
* tracing. * tracing.
*/ */
MarkDelayedChildren(&trc); gcmarker.markDelayedChildren();
JS_ASSERT(rt->gcMarkLaterCount == 0);
rt->gcMarkingTracer = NULL; rt->gcMarkingTracer = NULL;
@ -3002,11 +2964,11 @@ GC(JSContext *cx GCTIMER_PARAM)
* rather than nest badly and leave the unmarked newborn to be swept. * rather than nest badly and leave the unmarked newborn to be swept.
* *
* We first sweep atom state so we can use js_IsAboutToBeFinalized on * We first sweep atom state so we can use js_IsAboutToBeFinalized on
* JSString or jsdouble held in a hashtable to check if the hashtable * JSString held in a hashtable to check if the hashtable entry can be
* entry can be freed. Note that even after the entry is freed, JSObject * freed. Note that even after the entry is freed, JSObject finalizers can
* finalizers can continue to access the corresponding jsdouble* and * continue to access the corresponding JSString* assuming that they are
* JSString* assuming that they are unique. This works since the * unique. This works since the atomization API must not be called during
* atomization API must not be called during GC. * the GC.
*/ */
TIMESTAMP(startSweep); TIMESTAMP(startSweep);
js_SweepAtomState(cx); js_SweepAtomState(cx);
@ -3022,9 +2984,8 @@ GC(JSContext *cx GCTIMER_PARAM)
/* /*
* We finalize iterators before other objects so the iterator can use the * We finalize iterators before other objects so the iterator can use the
* object which properties it enumerates over to finalize the enumeration * object which properties it enumerates over to finalize the enumeration
* state. We finalize objects before string, double and other GC things * state. We finalize objects before other GC things to ensure that
* things to ensure that object's finalizer can access them even if they * object's finalizer can access them even if they will be freed.
* will be freed.
*/ */
JS_ASSERT(!rt->gcEmptyArenaList); JS_ASSERT(!rt->gcEmptyArenaList);
FinalizeArenaList<JSObject, FinalizeObject>(cx, FINALIZE_OBJECT); FinalizeArenaList<JSObject, FinalizeObject>(cx, FINALIZE_OBJECT);
@ -3065,15 +3026,8 @@ GC(JSContext *cx GCTIMER_PARAM)
*/ */
js_SweepScriptFilenames(rt); js_SweepScriptFilenames(rt);
/* /* Slowify arrays we have accumulated. */
* Slowify arrays we have accumulated. gcmarker.slowifyArrays();
*/
while (!trc.arraysToSlowify.empty()) {
JSObject *obj = trc.arraysToSlowify.back();
trc.arraysToSlowify.popBack();
if (IsMarkedGCThing(obj))
obj->makeDenseArraySlow(cx);
}
/* /*
* Destroy arenas after we finished the sweeping so finalizers can safely * Destroy arenas after we finished the sweeping so finalizers can safely

View File

@ -89,7 +89,7 @@ struct Compiler;
/* Struct typedefs. */ /* Struct typedefs. */
typedef struct JSArgumentFormatMap JSArgumentFormatMap; typedef struct JSArgumentFormatMap JSArgumentFormatMap;
typedef struct JSCodeGenerator JSCodeGenerator; typedef struct JSCodeGenerator JSCodeGenerator;
typedef union JSGCThing JSGCThing; typedef struct JSGCThing JSGCThing;
typedef struct JSGenerator JSGenerator; typedef struct JSGenerator JSGenerator;
typedef struct JSNativeEnumerator JSNativeEnumerator; typedef struct JSNativeEnumerator JSNativeEnumerator;
typedef struct JSFunctionBox JSFunctionBox; typedef struct JSFunctionBox JSFunctionBox;

View File

@ -337,9 +337,15 @@ void XPCJSRuntime::TraceJS(JSTracer* trc, void* data)
static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc); static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
// Mark these roots as gray so the CC can walk them later. // Mark these roots as gray so the CC can walk them later.
uint32 oldColor = js_SetMarkColor(trc, XPC_GC_COLOR_GRAY); js::GCMarker *gcmarker = NULL;
if (IS_GC_MARKING_TRACER(trc)) {
gcmarker = static_cast<js::GCMarker *>(trc);
JS_ASSERT(gcmarker->getMarkColor() == XPC_GC_COLOR_BLACK);
gcmarker->setMarkColor(XPC_GC_COLOR_GRAY);
}
self->TraceXPConnectRoots(trc); self->TraceXPConnectRoots(trc);
js_SetMarkColor(trc, oldColor); if (gcmarker)
gcmarker->setMarkColor(XPC_GC_COLOR_BLACK);
} }
static void static void

View File

@ -411,6 +411,7 @@ private:
**************************************************************************** ****************************************************************************
***************************************************************************/ ***************************************************************************/
static const uint32 XPC_GC_COLOR_BLACK = 0;
static const uint32 XPC_GC_COLOR_GRAY = 1; static const uint32 XPC_GC_COLOR_GRAY = 1;
// We have a general rule internally that getters that return addref'd interface // We have a general rule internally that getters that return addref'd interface