mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Use mark stack for type objects, bug 679887.
This commit is contained in:
parent
6e0458f6d1
commit
7f4dcc90fb
@ -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 *)];
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user