Bug 790865 - Add more compartment assertions (r=terrence)

This commit is contained in:
Bill McCloskey 2012-09-14 17:19:53 -07:00
parent e3dfeea781
commit 64cccf1287
6 changed files with 93 additions and 0 deletions

View File

@ -3273,11 +3273,80 @@ ShouldPreserveJITCode(JSCompartment *c, int64_t currentTime)
return false;
}
#ifdef DEBUG
struct CompartmentCheckTracer : public JSTracer
{
Cell *src;
JSGCTraceKind srcKind;
JSCompartment *compartment;
};
static bool
InCrossCompartmentMap(JSObject *src, Cell *dst, JSGCTraceKind dstKind)
{
JSCompartment *srccomp = src->compartment();
if (dstKind == JSTRACE_OBJECT) {
Value key = ObjectValue(*static_cast<JSObject *>(dst));
WrapperMap::Ptr p = srccomp->crossCompartmentWrappers.lookup(key);
if (*p->value.unsafeGet() == ObjectValue(*src))
return true;
}
/*
* If the cross-compartment edge is caused by the debugger, then we don't
* know the right hashtable key, so we have to iterate.
*/
for (WrapperMap::Enum e(srccomp->crossCompartmentWrappers); !e.empty(); e.popFront()) {
if (e.front().key.wrapped == dst && ToMarkable(e.front().value) == src)
return true;
}
return false;
}
static void
CheckCompartmentCallback(JSTracer *trcArg, void **thingp, JSGCTraceKind kind)
{
CompartmentCheckTracer *trc = static_cast<CompartmentCheckTracer *>(trcArg);
Cell *thing = (Cell *)*thingp;
JS_ASSERT(thing->compartment() == trc->compartment ||
thing->compartment() == trc->runtime->atomsCompartment ||
(trc->srcKind == JSTRACE_OBJECT &&
InCrossCompartmentMap((JSObject *)trc->src, thing, kind)));
}
static void
CheckForCompartmentMismatches(JSRuntime *rt)
{
if (rt->gcDisableStrictProxyCheckingCount)
return;
CompartmentCheckTracer trc;
JS_TracerInit(&trc, rt, CheckCompartmentCallback);
for (CompartmentsIter c(rt); !c.done(); c.next()) {
trc.compartment = c;
for (size_t thingKind = 0; thingKind < FINALIZE_LAST; thingKind++) {
for (CellIterUnderGC i(c, AllocKind(thingKind)); !i.done(); i.next()) {
trc.src = i.getCell();
trc.srcKind = MapAllocToTraceKind(AllocKind(thingKind));
JS_TraceChildren(&trc, trc.src, trc.srcKind);
}
}
}
}
#endif
static void
BeginMarkPhase(JSRuntime *rt)
{
int64_t currentTime = PRMJ_Now();
#ifdef DEBUG
CheckForCompartmentMismatches(rt);
#endif
rt->gcIsFull = true;
DebugOnly<bool> any = false;
for (CompartmentsIter c(rt); !c.done(); c.next()) {

View File

@ -2063,6 +2063,9 @@ TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
JSProtoKey key, JSObject *proto_, bool unknown,
bool isDOM)
{
JS_ASSERT_IF(script, cx->compartment == script->compartment());
JS_ASSERT_IF(proto_, cx->compartment == proto_->compartment());
RootedObject proto(cx, proto_);
TypeObject *object = gc::NewGCThing<TypeObject>(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject));
if (!object)
@ -5579,6 +5582,8 @@ JSObject::shouldSplicePrototype(JSContext *cx)
bool
JSObject::splicePrototype(JSContext *cx, JSObject *proto_)
{
JS_ASSERT(cx->compartment == compartment());
RootedObject proto(cx, proto_);
RootedObject self(cx, this);
@ -5639,6 +5644,7 @@ TypeObject *
JSObject::makeLazyType(JSContext *cx)
{
JS_ASSERT(hasLazyType());
JS_ASSERT(cx->compartment == compartment());
RootedObject self(cx, this);
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(getClass());
@ -5749,6 +5755,8 @@ JSObject::setNewTypeUnknown(JSContext *cx)
TypeObject *
JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
{
JS_ASSERT(cx->compartment == compartment());
TypeObjectSet &table = cx->compartment->newTypeObjects;
if (!table.initialized() && !table.init())
@ -5837,6 +5845,9 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
TypeObject *
JSCompartment::getLazyType(JSContext *cx, JSObject *proto_)
{
JS_ASSERT(cx->compartment == this);
JS_ASSERT_IF(proto_, cx->compartment == proto_->compartment());
RootedObject proto(cx, proto_);
MaybeCheckStackRoots(cx);

View File

@ -2660,6 +2660,9 @@ bool
JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
TradeGutsReserved &reserved)
{
JS_ASSERT(a->compartment() == b->compartment());
AutoCompartment ac(cx, a);
/*
* When performing multiple swaps between objects which may have different
* numbers of fixed slots, we reserve all space ahead of time so that the

View File

@ -663,6 +663,7 @@ JSObject::setSingletonType(JSContext *cx, js::HandleObject obj)
inline js::types::TypeObject *
JSObject::getType(JSContext *cx)
{
JS_ASSERT(cx->compartment == compartment());
if (hasLazyType())
return makeLazyType(cx);
return type_;
@ -672,6 +673,7 @@ JSObject::getType(JSContext *cx)
JSObject::clearType(JSContext *cx, js::HandleObject obj)
{
JS_ASSERT(!obj->hasSingletonType());
JS_ASSERT(cx->compartment == obj->compartment());
js::types::TypeObject *type = cx->compartment->getEmptyType(cx);
if (!type)
@ -692,6 +694,7 @@ JSObject::setType(js::types::TypeObject *newType)
JS_ASSERT_IF(hasSpecialEquality(),
newType->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
JS_ASSERT(!hasSingletonType());
JS_ASSERT(compartment() == newType->compartment());
type_ = newType;
}
@ -824,6 +827,7 @@ JSObject::create(JSContext *cx, js::gc::AllocKind kind,
JS_ASSERT(shape && type);
JS_ASSERT(!!dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()) == !!slots);
JS_ASSERT(js::gc::GetGCKindSlots(kind, shape->getObjectClass()) == shape->numFixedSlots());
JS_ASSERT(cx->compartment == type->compartment());
JSObject *obj = js_NewGCObject(cx, kind);
if (!obj)
@ -852,6 +856,7 @@ JSObject::createDenseArray(JSContext *cx, js::gc::AllocKind kind,
{
JS_ASSERT(shape && type);
JS_ASSERT(shape->getObjectClass() == &js::ArrayClass);
JS_ASSERT(cx->compartment == type->compartment());
/*
* Dense arrays are non-native, and never have properties to store.

View File

@ -3059,6 +3059,7 @@ js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_,
JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
JS_ASSERT_IF(construct, cx->compartment == construct->compartment());
JS_ASSERT_IF(call && cx->compartment != call->compartment(), priv.get() == ObjectValue(*call));
bool fun = call || construct;
Class *clasp;
if (fun)

View File

@ -928,6 +928,7 @@ JSObject::rollbackProperties(JSContext *cx, uint32_t slotSpan)
Shape *
JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *newShape)
{
JS_ASSERT(cx->compartment == oldShape->compartment());
JS_ASSERT_IF(oldShape != lastProperty(),
inDictionaryMode() &&
nativeLookupNoAllocation(oldShape->propidRef()) == oldShape);
@ -1202,6 +1203,9 @@ InitialShapeEntry::match(const InitialShapeEntry &key, const Lookup &lookup)
EmptyShape::getInitialShape(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent,
AllocKind kind, uint32_t objectFlags)
{
JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
InitialShapeSet &table = cx->compartment->initialShapes;
if (!table.initialized() && !table.init())