[INFER] Use mark stack for type objects, bug 679887.

This commit is contained in:
Brian Hackett 2011-08-26 09:50:48 -07:00
parent 6e0458f6d1
commit 7f4dcc90fb
7 changed files with 166 additions and 106 deletions

View File

@ -423,6 +423,7 @@ 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

@ -531,8 +531,7 @@ JSCompartment::markTypes(JSTracer *trc)
MarkObject(trc, *object, "mark_types_singleton");
} else {
types::TypeObject *object = reinterpret_cast<types::TypeObject *>(thing);
if (!object->isMarked())
object->trace(trc);
MarkTypeObject(trc, object, "object_root");
}
}
}

View File

@ -1537,6 +1537,7 @@ GCMarker::GCMarker(JSContext *cx)
unmarkedArenaStackTop(MarkingDelay::stackBottom()),
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))
{
@ -1798,8 +1799,7 @@ AutoGCRooter::trace(JSTracer *trc)
case TYPE: {
types::TypeObject *type = static_cast<types::AutoTypeRooter *>(this)->type;
if (!type->isMarked())
type->trace(trc);
MarkTypeObject(trc, type, "js::AutoTypeRooter");
return;
}

View File

@ -1393,6 +1393,7 @@ 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);
struct GCMarker : public JSTracer {
@ -1416,6 +1417,7 @@ struct GCMarker : public JSTracer {
MarkStack<JSObject *> objStack;
MarkStack<JSRope *> ropeStack;
MarkStack<types::TypeObject *> typeStack;
MarkStack<JSXML *> xmlStack;
MarkStack<LargeMarkItem> largeStack;
@ -1440,6 +1442,7 @@ struct GCMarker : public JSTracer {
bool isMarkStackEmpty() {
return objStack.isEmpty() &&
ropeStack.isEmpty() &&
typeStack.isEmpty() &&
xmlStack.isEmpty() &&
largeStack.isEmpty();
}
@ -1456,6 +1459,11 @@ struct GCMarker : public JSTracer {
delayMarkingChildren(rope);
}
void pushType(types::TypeObject *type) {
if (!typeStack.push(type))
delayMarkingChildren(type);
}
void pushXML(JSXML *xml) {
if (!xmlStack.push(xml))
delayMarkingChildren(xml);

View File

@ -100,6 +100,9 @@ PushMarkStack(GCMarker *gcmarker, JSShortString *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, JSString *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing);
template<typename T>
static inline void
CheckMarkedThing(JSTracer *trc, T *thing)
@ -145,41 +148,6 @@ Mark(JSTracer *trc, T *thing)
#endif
}
/*
* Alternative to Mark() which can be used when the thing is known to be in the
* correct compartment (if we are in a per-compartment GC) and which is inline.
*/
template<typename T>
inline void
InlineMark(JSTracer *trc, T *thing, const char *name)
{
JS_SET_TRACING_NAME(trc, name);
CheckMarkedThing(trc, thing);
if (IS_GC_MARKING_TRACER(trc))
PushMarkStack(static_cast<GCMarker *>(trc), thing);
else
trc->callback(trc, (void *)thing, GetGCThingTraceKind(thing));
#ifdef DEBUG
trc->debugPrinter = NULL;
trc->debugPrintArg = NULL;
#endif
}
inline void
InlineMarkId(JSTracer *trc, jsid id, const char *name)
{
if (JSID_IS_STRING(id)) {
JSString *str = JSID_TO_STRING(id);
if (!str->isStaticAtom())
InlineMark(trc, str, name);
} else if (JS_UNLIKELY(JSID_IS_OBJECT(id))) {
InlineMark(trc, JSID_TO_OBJECT(id), name);
}
}
void
MarkString(JSTracer *trc, JSString *str)
{
@ -235,6 +203,25 @@ MarkShape(JSTracer *trc, const Shape *shape, const char *name)
Mark(trc, shape);
}
void
MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name)
{
JS_ASSERT(trc);
JS_ASSERT(type);
JS_SET_TRACING_NAME(trc, name);
if (type == &types::emptyTypeObject)
return;
Mark(trc, type);
if (IS_GC_MARKING_TRACER(trc)) {
/* Mark parts of a type object skipped by ScanTypeObject. */
if (type->singleton)
MarkObject(trc, *type->singleton, "type_singleton");
if (type->functionScript)
js_TraceScript(trc, type->functionScript, NULL);
}
}
#if JS_HAS_XML_SUPPORT
void
MarkXML(JSTracer *trc, JSXML *xml, const char *name)
@ -276,6 +263,16 @@ PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
gcmarker->pushObject(thing);
}
void
PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
{
JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushType(thing);
}
void
PushMarkStack(GCMarker *gcmarker, JSShortString *thing)
{
@ -382,6 +379,9 @@ MarkKind(JSTracer *trc, void *thing, uint32 kind)
case JSTRACE_SHAPE:
Mark(trc, reinterpret_cast<Shape *>(thing));
break;
case JSTRACE_TYPE_OBJECT:
Mark(trc, reinterpret_cast<types::TypeObject *>(thing));
break;
#if JS_HAS_XML_SUPPORT
case JSTRACE_XML:
Mark(trc, reinterpret_cast<JSXML *>(thing));
@ -516,12 +516,7 @@ MarkRoot(JSTracer *trc, const Shape *thing, const char *name)
void
MarkRoot(JSTracer *trc, types::TypeObject *thing, const char *name)
{
JS_ASSERT(trc);
JS_ASSERT(thing);
JS_SET_TRACING_NAME(trc, name);
JSRuntime *rt = trc->context->runtime;
if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment)
thing->trace(trc, false);
MarkTypeObject(trc, thing, name);
}
void
@ -667,23 +662,33 @@ ScanObject(GCMarker *gcmarker, JSObject *obj)
return;
types::TypeObject *type = obj->gctype();
if (type != &types::emptyTypeObject && !type->isMarked())
type->trace(gcmarker, /* weak = */ true);
if (type != &types::emptyTypeObject)
PushMarkStack(gcmarker, type);
if (JSObject *parent = obj->getParent())
PushMarkStack(gcmarker, parent);
if (!obj->isDenseArray() && obj->newType && !obj->newType->isMarked())
obj->newType->trace(gcmarker);
/*
* Call the trace hook if necessary, and check for a newType on objects
* which are not dense arrays (dense arrays have trace hooks).
*/
Class *clasp = obj->getClass();
if (clasp->trace) {
if (obj->isDenseArray() && obj->getDenseArrayInitializedLength() > LARGE_OBJECT_CHUNK_SIZE) {
if (!gcmarker->largeStack.push(LargeMarkItem(obj))) {
if (clasp == &js_ArrayClass) {
if (obj->getDenseArrayInitializedLength() > LARGE_OBJECT_CHUNK_SIZE) {
if (!gcmarker->largeStack.push(LargeMarkItem(obj)))
clasp->trace(gcmarker, obj);
} else {
clasp->trace(gcmarker, obj);
}
} else {
if (obj->newType)
PushMarkStack(gcmarker, obj->newType);
clasp->trace(gcmarker, obj);
}
} else {
if (obj->newType)
PushMarkStack(gcmarker, obj->newType);
}
if (obj->isNative()) {
@ -746,13 +751,11 @@ MarkChildren(JSTracer *trc, JSObject *obj)
if (obj->isNewborn())
return;
types::TypeObject *type = obj->gctype();
if (type != &types::emptyTypeObject)
type->trace(trc, /* weak = */ true);
MarkTypeObject(trc, obj->gctype(), "type");
/* Trace universal (ops-independent) members. */
if (!obj->isDenseArray() && obj->newType)
obj->newType->trace(trc);
MarkTypeObject(trc, obj->newType, "new_type");
if (JSObject *parent = obj->getParent())
MarkObject(trc, *parent, "parent");
@ -803,6 +806,81 @@ restart:
goto restart;
}
static void
ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
{
if (!type->singleton) {
unsigned count = type->getPropertyCount();
for (unsigned i = 0; i < count; i++) {
types::Property *prop = type->getProperty(i);
if (prop && JSID_IS_STRING(prop->id)) {
JSString *str = JSID_TO_STRING(prop->id);
if (!str->isStaticAtom())
PushMarkStack(gcmarker, str);
}
}
}
if (type->emptyShapes) {
int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
for (int i = 0; i < count; i++) {
if (type->emptyShapes[i])
PushMarkStack(gcmarker, type->emptyShapes[i]);
}
}
if (type->proto)
PushMarkStack(gcmarker, type->proto);
if (type->newScript) {
js_TraceScript(gcmarker, type->newScript->script, NULL);
PushMarkStack(gcmarker, type->newScript->shape);
}
/*
* Don't need to trace singleton or functionScript, an object with this
* type must have already been traced and it will also hold a reference
* on the script (singleton and functionScript types cannot be the newType
* of another object). Attempts to mark type objects directly must use
* MarkTypeObject, which will itself mark these extra bits.
*/
}
void
MarkChildren(JSTracer *trc, types::TypeObject *type)
{
if (!type->singleton) {
unsigned count = type->getPropertyCount();
for (unsigned i = 0; i < count; i++) {
types::Property *prop = type->getProperty(i);
if (prop)
MarkId(trc, prop->id, "type_prop");
}
}
if (type->emptyShapes) {
int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
for (int i = 0; i < count; i++) {
if (type->emptyShapes[i])
MarkShape(trc, type->emptyShapes[i], "empty_shape");
}
}
if (type->proto)
MarkObject(trc, *type->proto, "type_proto");
if (type->singleton)
MarkObject(trc, *type->singleton, "type_singleton");
if (type->newScript) {
js_TraceScript(trc, type->newScript->script, NULL);
MarkShape(trc, type->newScript->shape, "type_new_shape");
}
if (type->functionScript)
js_TraceScript(trc, type->functionScript, NULL);
}
#ifdef JS_HAS_XML_SUPPORT
void
MarkChildren(JSTracer *trc, JSXML *xml)
@ -826,6 +904,9 @@ GCMarker::drainMarkStack()
while (!objStack.isEmpty())
ScanObject(this, objStack.pop());
while (!typeStack.isEmpty())
ScanTypeObject(this, typeStack.pop());
while (!xmlStack.isEmpty())
MarkChildren(this, xmlStack.pop());
@ -865,6 +946,10 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
MarkChildren(trc, (js::Shape *)thing);
break;
case JSTRACE_TYPE_OBJECT:
MarkChildren(trc, (types::TypeObject *)thing);
break;
#if JS_HAS_XML_SUPPORT
case JSTRACE_XML:
MarkChildren(trc, (JSXML *)thing);
@ -881,56 +966,21 @@ JSObject::scanSlots(GCMarker *gcmarker)
* branching inside nativeGetSlot().
*/
JS_ASSERT(slotSpan() <= numSlots());
uint32 nslots = slotSpan();
uint32 nfixed = numFixedSlots();
uint32 i;
for (i = 0; i < nslots && i < nfixed; i++)
ScanValue(gcmarker, fixedSlots()[i]);
for (; i < nslots; i++)
ScanValue(gcmarker, slots[i - nfixed]);
}
void
js::types::TypeObject::trace(JSTracer *trc, bool weak)
{
/*
* Only mark types if the Mark/Sweep GC is running; the bit won't be
* cleared by the cycle collector. Also, don't mark for weak references
* from singleton JS objects, as if there are no outstanding refs we will
* destroy the type object and revert the JS object to a lazy type.
*/
if (IS_GC_MARKING_TRACER(trc) && (!weak || !singleton)) {
JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment,
compartment() == trc->context->runtime->gcCurrentCompartment);
markIfUnmarked(static_cast<GCMarker *>(trc)->getMarkColor());
}
unsigned count = getPropertyCount();
for (unsigned i = 0; i < count; i++) {
Property *prop = getProperty(i);
if (prop)
InlineMarkId(trc, prop->id, "type_prop");
}
if (emptyShapes) {
int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
for (int i = 0; i < count; i++) {
if (emptyShapes[i])
InlineMark(trc, emptyShapes[i], "empty_shape");
unsigned i, nslots = slotSpan();
if (slots) {
unsigned nfixed = numFixedSlots();
if (nslots > nfixed) {
Value *vp = fixedSlots();
for (i = 0; i < nfixed; i++, vp++)
ScanValue(gcmarker, *vp);
vp = slots;
for (; i < nslots; i++, vp++)
ScanValue(gcmarker, *vp);
return;
}
}
if (proto)
InlineMark(trc, proto, "type_proto");
if (singleton)
InlineMark(trc, singleton, "type_singleton");
if (newScript) {
js_TraceScript(trc, newScript->script, NULL);
InlineMark(trc, newScript->shape, "new_shape");
}
if (functionScript)
js_TraceScript(trc, functionScript, NULL);
JS_ASSERT(nslots <= numFixedSlots());
Value *vp = fixedSlots();
for (i = 0; i < nslots; i++, vp++)
ScanValue(gcmarker, *vp);
}

View File

@ -76,6 +76,9 @@ MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
void
MarkShape(JSTracer *trc, const Shape *shape, const char *name);
void
MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name);
void
MarkXML(JSTracer *trc, JSXML *xml, const char *name);

View File

@ -844,7 +844,6 @@ struct TypeObject : gc::Cell
void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
void print(JSContext *cx);
void trace(JSTracer *trc, bool weak = false);
inline void clearProperties();
inline void sweep(JSContext *cx);