mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 579100 - various GC cleanups. r=anygregor
This commit is contained in:
parent
4c5fd024ab
commit
248a67333b
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
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);
|
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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user