Bug 708382 - GC marking - merging string and object stacks. r=wmccloskey

--HG--
extra : rebase_source : ca47672218af276ed0bbdfd53add6207c524179b
This commit is contained in:
Igor Bukanov 2011-12-08 10:29:43 +01:00
parent a83337c3b7
commit f902c0a6df
4 changed files with 43 additions and 31 deletions

View File

@ -439,7 +439,6 @@ struct JSRuntime
/* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */
void *gcMarkStackObjs[js::OBJECT_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackRopes[js::ROPES_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackTypes[js::TYPE_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackXMLs[js::XML_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackLarges[js::LARGE_MARK_STACK_SIZE / sizeof(void *)];

View File

@ -1736,7 +1736,6 @@ GCMarker::GCMarker(JSContext *cx)
: color(BLACK),
unmarkedArenaStackTop(NULL),
objStack(cx->runtime->gcMarkStackObjs, sizeof(cx->runtime->gcMarkStackObjs)),
ropeStack(cx->runtime->gcMarkStackRopes, sizeof(cx->runtime->gcMarkStackRopes)),
typeStack(cx->runtime->gcMarkStackTypes, sizeof(cx->runtime->gcMarkStackTypes)),
xmlStack(cx->runtime->gcMarkStackXMLs, sizeof(cx->runtime->gcMarkStackXMLs)),
largeStack(cx->runtime->gcMarkStackLarges, sizeof(cx->runtime->gcMarkStackLarges))

View File

@ -1631,7 +1631,6 @@ struct LargeMarkItem
};
static const size_t OBJECT_MARK_STACK_SIZE = 32768 * sizeof(JSObject *);
static const size_t ROPES_MARK_STACK_SIZE = 1024 * sizeof(JSString *);
static const size_t XML_MARK_STACK_SIZE = 1024 * sizeof(JSXML *);
static const size_t TYPE_MARK_STACK_SIZE = 1024 * sizeof(types::TypeObject *);
static const size_t LARGE_MARK_STACK_SIZE = 64 * sizeof(LargeMarkItem);
@ -1654,8 +1653,7 @@ struct GCMarker : public JSTracer {
void dumpConservativeRoots();
#endif
MarkStack<JSObject *> objStack;
MarkStack<JSRope *> ropeStack;
MarkStack<void *> objStack;
MarkStack<types::TypeObject *> typeStack;
MarkStack<JSXML *> xmlStack;
MarkStack<LargeMarkItem> largeStack;
@ -1687,7 +1685,6 @@ struct GCMarker : public JSTracer {
bool isMarkStackEmpty() {
return objStack.isEmpty() &&
ropeStack.isEmpty() &&
typeStack.isEmpty() &&
xmlStack.isEmpty() &&
largeStack.isEmpty();
@ -1700,11 +1697,6 @@ struct GCMarker : public JSTracer {
delayMarkingChildren(obj);
}
void pushRope(JSRope *rope) {
if (!ropeStack.push(rope))
delayMarkingChildren(rope);
}
void pushType(types::TypeObject *type) {
if (!typeStack.push(type))
delayMarkingChildren(type);

View File

@ -732,11 +732,22 @@ ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
}
}
/*
* The function tries to scan the whole rope tree using the marking stack as
* temporary storage. If that becomes full, the unscanned ropes are added to
* the delayed marking list. When the function returns, the marking stack is
* at the same depth as it was on entry.
*
* The function relies on the fact that a rope can only point to other ropes or
* linear strings, it cannot refer to other GC things of other types.
*/
static void
ScanRope(GCMarker *gcmarker, JSRope *rope)
{
JS_ASSERT(rope->JSString::isRope());
do {
unsigned savedTos = gcmarker->objStack.tos;
for (;;) {
JS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
JS_ASSERT(rope->JSString::isRope());
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, rope);
JS_ASSERT(rope->isMarked());
JSRope *next = NULL;
@ -755,16 +766,33 @@ ScanRope(GCMarker *gcmarker, JSRope *rope)
ScanLinearString(gcmarker, &left->asLinear());
} else {
/*
* Both children are ropes, set aside the right one to scan
* it later.
* When both children are ropes, set aside the right one to
* scan it later.
*/
if (next)
gcmarker->pushRope(next);
if (next && !gcmarker->objStack.push(next))
gcmarker->delayMarkingChildren(next);
next = &left->asRope();
}
}
rope = next;
} while (rope);
if (next) {
rope = next;
} else if (savedTos != gcmarker->objStack.tos) {
JS_ASSERT(savedTos < gcmarker->objStack.tos);
rope = static_cast<JSRope *>(gcmarker->objStack.pop());
} else {
break;
}
}
JS_ASSERT(savedTos == gcmarker->objStack.tos);
}
static inline void
ScanString(GCMarker *gcmarker, JSString *str)
{
if (str->isLinear())
ScanLinearString(gcmarker, &str->asLinear());
else
ScanRope(gcmarker, &str->asRope());
}
static inline void
@ -773,15 +801,12 @@ PushMarkStack(GCMarker *gcmarker, JSString *str)
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
/*
* We scan the string directly rather than pushing on the stack except
* when we have a rope and both its children are also ropes.
* As string can only refer to other strings we fully scan its GC graph
* using the explicit stack when navigating the rope tree to avoid
* dealing with strings on the stack in drainMarkStack.
*/
if (str->markIfUnmarked()) {
if (str->isLinear())
ScanLinearString(gcmarker, &str->asLinear());
else
ScanRope(gcmarker, &str->asRope());
}
if (str->markIfUnmarked())
ScanString(gcmarker, str);
}
static const uintN LARGE_OBJECT_CHUNK_SIZE = 2048;
@ -1053,11 +1078,8 @@ GCMarker::drainMarkStack()
rt->gcCheckCompartment = rt->gcCurrentCompartment;
while (!isMarkStackEmpty()) {
while (!ropeStack.isEmpty())
ScanRope(this, ropeStack.pop());
while (!objStack.isEmpty())
ScanObject(this, objStack.pop());
ScanObject(this, static_cast<JSObject *>(objStack.pop()));
while (!typeStack.isEmpty())
ScanTypeObject(this, typeStack.pop());