зеркало из https://github.com/mozilla/gecko-dev.git
bug 579100 - various GC cleanups. r=anygregor
This commit is contained in:
Родитель
d81549aaeb
Коммит
d024da7d92
|
@ -1012,11 +1012,9 @@ array_trace(JSTracer *trc, JSObject *obj)
|
|||
MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems");
|
||||
}
|
||||
|
||||
if (trc == trc->context->runtime->gcMarkingTracer &&
|
||||
holes > MIN_SPARSE_INDEX &&
|
||||
holes > capacity / 4 * 3) {
|
||||
if (IS_GC_MARKING_TRACER(trc) && holes > MIN_SPARSE_INDEX && holes > capacity / 4 * 3) {
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1171,6 +1171,50 @@ typedef HashMap<Value, Value, WrapperHasher, SystemAllocPolicy> WrapperMap;
|
|||
class AutoValueVector;
|
||||
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 */
|
||||
|
||||
struct JSCompartment {
|
||||
|
@ -1197,11 +1241,6 @@ struct JSCompartment {
|
|||
void sweep(JSContext *cx);
|
||||
};
|
||||
|
||||
struct JSGCTracer : public JSTracer {
|
||||
uint32 color;
|
||||
js::Vector<JSObject *, 0, js::SystemAllocPolicy> arraysToSlowify;
|
||||
};
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked);
|
||||
|
||||
|
@ -1251,7 +1290,7 @@ struct JSRuntime {
|
|||
size_t gcMaxMallocBytes;
|
||||
uint32 gcEmptyArenaPoolLifespan;
|
||||
uint32 gcNumber;
|
||||
JSGCTracer *gcMarkingTracer;
|
||||
js::GCMarker *gcMarkingTracer;
|
||||
uint32 gcTriggerFactor;
|
||||
size_t gcTriggerBytes;
|
||||
volatile JSBool gcIsNeeded;
|
||||
|
@ -1290,12 +1329,6 @@ struct JSRuntime {
|
|||
*/
|
||||
volatile ptrdiff_t gcMallocBytes;
|
||||
|
||||
/* See comments before DelayMarkingChildren is jsgc.cpp. */
|
||||
JSGCArena *gcUnmarkedArenaStackTop;
|
||||
#ifdef DEBUG
|
||||
size_t gcMarkLaterCount;
|
||||
#endif
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSBackgroundThread gcHelperThread;
|
||||
#endif
|
||||
|
|
292
js/src/jsgc.cpp
292
js/src/jsgc.cpp
|
@ -240,12 +240,9 @@ JS_STATIC_ASSERT(sizeof(JSFunction) % GC_CELL_SIZE == 0);
|
|||
JS_STATIC_ASSERT(sizeof(JSXML) % GC_CELL_SIZE == 0);
|
||||
#endif
|
||||
|
||||
JS_STATIC_ASSERT(GC_CELL_SIZE == sizeof(jsdouble));
|
||||
const size_t DOUBLES_PER_ARENA = GC_CELLS_PER_ARENA;
|
||||
|
||||
struct JSGCArenaInfo {
|
||||
/*
|
||||
* Allocation list for the arena or NULL if the arena holds double values.
|
||||
* Allocation list for the arena.
|
||||
*/
|
||||
JSGCArenaList *list;
|
||||
|
||||
|
@ -571,9 +568,8 @@ GCArenaIndexToThing(JSGCArena *a, JSGCArenaInfo *ainfo, size_t index)
|
|||
/*
|
||||
* The private JSGCThing struct, which describes a JSRuntime.gcFreeList element.
|
||||
*/
|
||||
union JSGCThing {
|
||||
struct JSGCThing {
|
||||
JSGCThing *link;
|
||||
double asDouble;
|
||||
};
|
||||
|
||||
static inline JSGCThing *
|
||||
|
@ -883,25 +879,6 @@ js_IsAboutToBeFinalized(void *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_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
|
||||
* 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
|
||||
* arena stored in JSGCMarkingDelay. The first field, JSGCMarkingDelay::link,
|
||||
* links all arenas with delayed things into a stack list with the pointer to
|
||||
* stack top in JSRuntime::gcUnmarkedArenaStackTop. DelayMarkingChildren adds
|
||||
* arenas to the stack as necessary while MarkDelayedChildren pops the arenas
|
||||
* stack top in JSRuntime::gcUnmarkedArenaStackTop. delayMarkingChildren adds
|
||||
* arenas to the stack as necessary while markDelayedChildren pops the arenas
|
||||
* from the stack until it empties.
|
||||
*
|
||||
* 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
|
||||
* in the arena but rather tells the intervals containing
|
||||
* 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
|
||||
* 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
|
||||
|
@ -1943,11 +1922,12 @@ ThingsPerUnmarkedBit(unsigned thingSize)
|
|||
return JS_HOWMANY(ThingsPerArena(thingSize), JS_BITS_PER_WORD);
|
||||
}
|
||||
|
||||
static void
|
||||
DelayMarkingChildren(JSRuntime *rt, void *thing)
|
||||
void
|
||||
GCMarker::delayMarkingChildren(void *thing)
|
||||
{
|
||||
JS_ASSERT(this == context->runtime->gcMarkingTracer);
|
||||
JS_ASSERT(IsMarkedGCThing(thing));
|
||||
METER(rt->gcStats.unmarked++);
|
||||
METER(context->runtime->gcStats.unmarked++);
|
||||
|
||||
JSGCArena *a = JSGCArena::fromGCThing(thing);
|
||||
JSGCArenaInfo *ainfo = a->getInfo();
|
||||
|
@ -1960,7 +1940,7 @@ DelayMarkingChildren(JSRuntime *rt, void *thing)
|
|||
|
||||
jsuword bit = jsuword(1) << unmarkedBitIndex;
|
||||
if (markingDelay->unmarkedChildren != 0) {
|
||||
JS_ASSERT(rt->gcUnmarkedArenaStackTop);
|
||||
JS_ASSERT(unmarkedArenaStackTop);
|
||||
if (markingDelay->unmarkedChildren & bit) {
|
||||
/* bit already covers things with children to mark later. */
|
||||
return;
|
||||
|
@ -1977,58 +1957,53 @@ DelayMarkingChildren(JSRuntime *rt, void *thing)
|
|||
* even when the stack contains one element, we make prevUnmarked
|
||||
* for the arena at the bottom to point to itself.
|
||||
*
|
||||
* See comments in MarkDelayedChildren.
|
||||
* See comments in markDelayedChildren.
|
||||
*/
|
||||
markingDelay->unmarkedChildren = bit;
|
||||
if (!markingDelay->link) {
|
||||
if (!rt->gcUnmarkedArenaStackTop) {
|
||||
if (!unmarkedArenaStackTop) {
|
||||
/* Stack was empty, mark the arena as the bottom element. */
|
||||
markingDelay->link = a;
|
||||
} else {
|
||||
JS_ASSERT(rt->gcUnmarkedArenaStackTop->getMarkingDelay()->link);
|
||||
markingDelay->link = rt->gcUnmarkedArenaStackTop;
|
||||
JS_ASSERT(unmarkedArenaStackTop->getMarkingDelay()->link);
|
||||
markingDelay->link = unmarkedArenaStackTop;
|
||||
}
|
||||
rt->gcUnmarkedArenaStackTop = a;
|
||||
unmarkedArenaStackTop = a;
|
||||
}
|
||||
JS_ASSERT(rt->gcUnmarkedArenaStackTop);
|
||||
JS_ASSERT(unmarkedArenaStackTop);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
rt->gcMarkLaterCount += ThingsPerUnmarkedBit(ainfo->list->thingSize);
|
||||
METER_UPDATE_MAX(rt->gcStats.maxunmarked, rt->gcMarkLaterCount);
|
||||
markLaterCount += ThingsPerUnmarkedBit(ainfo->list->thingSize);
|
||||
METER_UPDATE_MAX(context->runtime->gcStats.maxunmarked, markLaterCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
MarkDelayedChildren(JSTracer *trc)
|
||||
JS_FRIEND_API(void)
|
||||
GCMarker::markDelayedChildren()
|
||||
{
|
||||
JSRuntime *rt;
|
||||
JSGCArena *a, *aprev;
|
||||
unsigned thingSize, traceKind;
|
||||
unsigned thingsPerUnmarkedBit;
|
||||
unsigned unmarkedBitIndex, thingIndex, indexLimit, endIndex;
|
||||
JS_ASSERT(this == context->runtime->gcMarkingTracer);
|
||||
|
||||
rt = trc->context->runtime;
|
||||
a = rt->gcUnmarkedArenaStackTop;
|
||||
JSGCArena *a = unmarkedArenaStackTop;
|
||||
if (!a) {
|
||||
JS_ASSERT(rt->gcMarkLaterCount == 0);
|
||||
JS_ASSERT(markLaterCount == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* 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
|
||||
* itself.
|
||||
*/
|
||||
JSGCArenaInfo *ainfo = a->getInfo();
|
||||
JSGCMarkingDelay *markingDelay = a->getMarkingDelay();
|
||||
JS_ASSERT(markingDelay->link);
|
||||
JS_ASSERT(rt->gcUnmarkedArenaStackTop->getMarkingDelay()->link);
|
||||
thingSize = ainfo->list->thingSize;
|
||||
traceKind = GetFinalizableArenaTraceKind(ainfo);
|
||||
indexLimit = ThingsPerArena(thingSize);
|
||||
thingsPerUnmarkedBit = ThingsPerUnmarkedBit(thingSize);
|
||||
JS_ASSERT(unmarkedArenaStackTop->getMarkingDelay()->link);
|
||||
unsigned thingSize = ainfo->list->thingSize;
|
||||
unsigned traceKind = GetFinalizableArenaTraceKind(ainfo);
|
||||
unsigned indexLimit = ThingsPerArena(thingSize);
|
||||
unsigned thingsPerUnmarkedBit = ThingsPerUnmarkedBit(thingSize);
|
||||
|
||||
/*
|
||||
* We cannot use do-while loop here as a->unmarkedChildren can be zero
|
||||
|
@ -2036,14 +2011,14 @@ MarkDelayedChildren(JSTracer *trc)
|
|||
* comments after the loop.
|
||||
*/
|
||||
while (markingDelay->unmarkedChildren != 0) {
|
||||
unmarkedBitIndex = JS_FLOOR_LOG2W(markingDelay->unmarkedChildren);
|
||||
unsigned unmarkedBitIndex = JS_FLOOR_LOG2W(markingDelay->unmarkedChildren);
|
||||
markingDelay->unmarkedChildren &= ~(jsuword(1) << unmarkedBitIndex);
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(rt->gcMarkLaterCount >= thingsPerUnmarkedBit);
|
||||
rt->gcMarkLaterCount -= thingsPerUnmarkedBit;
|
||||
JS_ASSERT(markLaterCount >= thingsPerUnmarkedBit);
|
||||
markLaterCount -= thingsPerUnmarkedBit;
|
||||
#endif
|
||||
thingIndex = unmarkedBitIndex * thingsPerUnmarkedBit;
|
||||
endIndex = thingIndex + thingsPerUnmarkedBit;
|
||||
unsigned thingIndex = unmarkedBitIndex * thingsPerUnmarkedBit;
|
||||
unsigned endIndex = thingIndex + thingsPerUnmarkedBit;
|
||||
|
||||
/*
|
||||
* endIndex can go beyond the last allocated thing as the real
|
||||
|
@ -2056,7 +2031,7 @@ MarkDelayedChildren(JSTracer *trc)
|
|||
do {
|
||||
JS_ASSERT(thing < end);
|
||||
if (IsMarkedGCThing(thing))
|
||||
JS_TraceChildren(trc, thing, traceKind);
|
||||
JS_TraceChildren(this, thing, traceKind);
|
||||
thing += thingSize;
|
||||
} while (thing != end);
|
||||
}
|
||||
|
@ -2066,12 +2041,12 @@ MarkDelayedChildren(JSTracer *trc)
|
|||
* pop it from the stack if the arena is the stack's top.
|
||||
*
|
||||
* 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
|
||||
* of this arena until it becomes the top of the stack again.
|
||||
*/
|
||||
if (a == rt->gcUnmarkedArenaStackTop) {
|
||||
aprev = markingDelay->link;
|
||||
if (a == unmarkedArenaStackTop) {
|
||||
JSGCArena *aprev = markingDelay->link;
|
||||
markingDelay->link = NULL;
|
||||
if (a == aprev) {
|
||||
/*
|
||||
|
@ -2080,95 +2055,95 @@ MarkDelayedChildren(JSTracer *trc)
|
|||
*/
|
||||
break;
|
||||
}
|
||||
rt->gcUnmarkedArenaStackTop = a = aprev;
|
||||
unmarkedArenaStackTop = a = aprev;
|
||||
} else {
|
||||
a = rt->gcUnmarkedArenaStackTop;
|
||||
a = unmarkedArenaStackTop;
|
||||
}
|
||||
}
|
||||
JS_ASSERT(rt->gcUnmarkedArenaStackTop);
|
||||
JS_ASSERT(!rt->gcUnmarkedArenaStackTop->getMarkingDelay()->link);
|
||||
rt->gcUnmarkedArenaStackTop = NULL;
|
||||
JS_ASSERT(rt->gcMarkLaterCount == 0);
|
||||
JS_ASSERT(unmarkedArenaStackTop);
|
||||
JS_ASSERT(!unmarkedArenaStackTop->getMarkingDelay()->link);
|
||||
unmarkedArenaStackTop = NULL;
|
||||
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
|
||||
Mark(JSTracer *trc, void *thing, uint32 kind)
|
||||
{
|
||||
JSContext *cx;
|
||||
JSRuntime *rt;
|
||||
|
||||
JS_ASSERT(thing);
|
||||
JS_ASSERT(JS_IS_VALID_TRACE_KIND(kind));
|
||||
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)) {
|
||||
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 {
|
||||
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
|
||||
trc->debugPrinter = NULL;
|
||||
trc->debugPrintArg = NULL;
|
||||
#endif
|
||||
return; /* to avoid out: right_curl when DEBUG is not defined */
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2821,15 +2796,6 @@ struct GCTimer {
|
|||
# define GCTIMER_END(last) ((void) 0)
|
||||
#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
|
||||
|
||||
namespace js {
|
||||
|
@ -2959,29 +2925,25 @@ GC(JSContext *cx GCTIMER_PARAM)
|
|||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
rt->gcNumber++;
|
||||
JS_ASSERT(!rt->gcUnmarkedArenaStackTop);
|
||||
JS_ASSERT(rt->gcMarkLaterCount == 0);
|
||||
|
||||
/*
|
||||
* Mark phase.
|
||||
*/
|
||||
JSGCTracer trc;
|
||||
JS_TRACER_INIT(&trc, cx, NULL);
|
||||
trc.color = BLACK;
|
||||
rt->gcMarkingTracer = &trc;
|
||||
JS_ASSERT(IS_GC_MARKING_TRACER(&trc));
|
||||
|
||||
GCMarker gcmarker(cx);
|
||||
JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker));
|
||||
JS_ASSERT(gcmarker.getMarkColor() == BLACK);
|
||||
rt->gcMarkingTracer = &gcmarker;
|
||||
|
||||
for (JSGCChunkInfo **i = rt->gcChunks.begin(); i != rt->gcChunks.end(); ++i)
|
||||
(*i)->clearMarkBitmap();
|
||||
js_TraceRuntime(&trc);
|
||||
js_TraceRuntime(&gcmarker);
|
||||
js_MarkScriptFilenames(rt);
|
||||
|
||||
/*
|
||||
* Mark children of things that caused too deep recursion during the above
|
||||
* tracing.
|
||||
*/
|
||||
MarkDelayedChildren(&trc);
|
||||
JS_ASSERT(rt->gcMarkLaterCount == 0);
|
||||
gcmarker.markDelayedChildren();
|
||||
|
||||
rt->gcMarkingTracer = NULL;
|
||||
|
||||
|
@ -3002,11 +2964,11 @@ GC(JSContext *cx GCTIMER_PARAM)
|
|||
* rather than nest badly and leave the unmarked newborn to be swept.
|
||||
*
|
||||
* We first sweep atom state so we can use js_IsAboutToBeFinalized on
|
||||
* JSString or jsdouble held in a hashtable to check if the hashtable
|
||||
* entry can be freed. Note that even after the entry is freed, JSObject
|
||||
* finalizers can continue to access the corresponding jsdouble* and
|
||||
* JSString* assuming that they are unique. This works since the
|
||||
* atomization API must not be called during GC.
|
||||
* JSString held in a hashtable to check if the hashtable entry can be
|
||||
* freed. Note that even after the entry is freed, JSObject finalizers can
|
||||
* continue to access the corresponding JSString* assuming that they are
|
||||
* unique. This works since the atomization API must not be called during
|
||||
* the GC.
|
||||
*/
|
||||
TIMESTAMP(startSweep);
|
||||
js_SweepAtomState(cx);
|
||||
|
@ -3022,9 +2984,8 @@ GC(JSContext *cx GCTIMER_PARAM)
|
|||
/*
|
||||
* We finalize iterators before other objects so the iterator can use the
|
||||
* object which properties it enumerates over to finalize the enumeration
|
||||
* state. We finalize objects before string, double and other GC things
|
||||
* things to ensure that object's finalizer can access them even if they
|
||||
* will be freed.
|
||||
* state. We finalize objects before other GC things to ensure that
|
||||
* object's finalizer can access them even if they will be freed.
|
||||
*/
|
||||
JS_ASSERT(!rt->gcEmptyArenaList);
|
||||
FinalizeArenaList<JSObject, FinalizeObject>(cx, FINALIZE_OBJECT);
|
||||
|
@ -3065,15 +3026,8 @@ GC(JSContext *cx GCTIMER_PARAM)
|
|||
*/
|
||||
js_SweepScriptFilenames(rt);
|
||||
|
||||
/*
|
||||
* Slowify arrays we have accumulated.
|
||||
*/
|
||||
while (!trc.arraysToSlowify.empty()) {
|
||||
JSObject *obj = trc.arraysToSlowify.back();
|
||||
trc.arraysToSlowify.popBack();
|
||||
if (IsMarkedGCThing(obj))
|
||||
obj->makeDenseArraySlow(cx);
|
||||
}
|
||||
/* Slowify arrays we have accumulated. */
|
||||
gcmarker.slowifyArrays();
|
||||
|
||||
/*
|
||||
* Destroy arenas after we finished the sweeping so finalizers can safely
|
||||
|
|
|
@ -89,7 +89,7 @@ struct Compiler;
|
|||
/* Struct typedefs. */
|
||||
typedef struct JSArgumentFormatMap JSArgumentFormatMap;
|
||||
typedef struct JSCodeGenerator JSCodeGenerator;
|
||||
typedef union JSGCThing JSGCThing;
|
||||
typedef struct JSGCThing JSGCThing;
|
||||
typedef struct JSGenerator JSGenerator;
|
||||
typedef struct JSNativeEnumerator JSNativeEnumerator;
|
||||
typedef struct JSFunctionBox JSFunctionBox;
|
||||
|
|
|
@ -337,9 +337,15 @@ void XPCJSRuntime::TraceJS(JSTracer* trc, void* data)
|
|||
static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
|
||||
|
||||
// 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);
|
||||
js_SetMarkColor(trc, oldColor);
|
||||
if (gcmarker)
|
||||
gcmarker->setMarkColor(XPC_GC_COLOR_BLACK);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -411,6 +411,7 @@ private:
|
|||
****************************************************************************
|
||||
***************************************************************************/
|
||||
|
||||
static const uint32 XPC_GC_COLOR_BLACK = 0;
|
||||
static const uint32 XPC_GC_COLOR_GRAY = 1;
|
||||
|
||||
// We have a general rule internally that getters that return addref'd interface
|
||||
|
|
Загрузка…
Ссылка в новой задаче