mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 816054 - Assert wrappers are sensible when added to compartment map r=billm
--HG-- extra : rebase_source : 1089ac35de6ac4394e0ac9578257647e9bf25b92
This commit is contained in:
parent
96c58ac7d3
commit
98b772bfc1
@ -1571,7 +1571,6 @@ JS_TransplantObject(JSContext *cx, JSObject *origobjArg, JSObject *targetArg)
|
||||
AutoMaybeTouchDeadCompartments agc(cx);
|
||||
|
||||
JSCompartment *destination = target->compartment();
|
||||
WrapperMap &map = destination->crossCompartmentWrappers;
|
||||
Value origv = ObjectValue(*origobj);
|
||||
JSObject *newIdentity;
|
||||
|
||||
@ -1583,7 +1582,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobjArg, JSObject *targetArg)
|
||||
if (!origobj->swap(cx, target))
|
||||
MOZ_CRASH();
|
||||
newIdentity = origobj;
|
||||
} else if (WrapperMap::Ptr p = map.lookup(origv)) {
|
||||
} else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
|
||||
// There might already be a wrapper for the original object in
|
||||
// the new compartment. If there is, we use its identity and swap
|
||||
// in the contents of |target|.
|
||||
@ -1591,7 +1590,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobjArg, JSObject *targetArg)
|
||||
|
||||
// When we remove origv from the wrapper map, its wrapper, newIdentity,
|
||||
// must immediately cease to be a cross-compartment wrapper. Neuter it.
|
||||
map.remove(p);
|
||||
destination->removeWrapper(p);
|
||||
NukeCrossCompartmentWrapper(cx, newIdentity);
|
||||
|
||||
if (!newIdentity->swap(cx, target))
|
||||
@ -1615,7 +1614,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobjArg, JSObject *targetArg)
|
||||
JS_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
|
||||
if (!origobj->swap(cx, newIdentityWrapper))
|
||||
MOZ_CRASH();
|
||||
origobj->compartment()->crossCompartmentWrappers.put(ObjectValue(*newIdentity), origv);
|
||||
origobj->compartment()->putWrapper(ObjectValue(*newIdentity), origv);
|
||||
}
|
||||
|
||||
// The new identity object might be one of several things. Return it to avoid
|
||||
@ -1652,7 +1651,6 @@ js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
|
||||
JSObject *newWrapper;
|
||||
JSCompartment *destination = targetobj->compartment();
|
||||
WrapperMap &map = destination->crossCompartmentWrappers;
|
||||
|
||||
// |origv| is the map entry we're looking up. The map entries are going to
|
||||
// be for |origobj|, not |origwrapper|.
|
||||
@ -1660,14 +1658,14 @@ js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
|
||||
// There might already be a wrapper for the original object in the new
|
||||
// compartment.
|
||||
if (WrapperMap::Ptr p = map.lookup(origv)) {
|
||||
if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
|
||||
// There is. Make the existing cross-compartment wrapper a same-
|
||||
// compartment wrapper.
|
||||
newWrapper = &p->value.toObject();
|
||||
|
||||
// When we remove origv from the wrapper map, its wrapper, newWrapper,
|
||||
// must immediately cease to be a cross-compartment wrapper. Neuter it.
|
||||
map.remove(p);
|
||||
destination->removeWrapper(p);
|
||||
NukeCrossCompartmentWrapper(cx, newWrapper);
|
||||
|
||||
if (!newWrapper->swap(cx, targetwrapper))
|
||||
@ -1707,8 +1705,8 @@ js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
JS_ASSERT(Wrapper::wrappedObject(wrapperGuts) == targetobj);
|
||||
if (!origwrapper->swap(cx, wrapperGuts))
|
||||
MOZ_CRASH();
|
||||
origwrapper->compartment()->crossCompartmentWrappers.put(ObjectValue(*targetobj),
|
||||
ObjectValue(*origwrapper));
|
||||
origwrapper->compartment()->putWrapper(ObjectValue(*targetobj),
|
||||
ObjectValue(*origwrapper));
|
||||
}
|
||||
|
||||
return newWrapper;
|
||||
|
@ -227,6 +227,17 @@ WrapForSameCompartment(JSContext *cx, HandleObject obj, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::putWrapper(const CrossCompartmentKey &wrapped, const js::Value &wrapper)
|
||||
{
|
||||
JS_ASSERT(wrapped.wrapped);
|
||||
JS_ASSERT_IF(wrapped.kind == CrossCompartmentKey::StringWrapper, wrapper.isString());
|
||||
JS_ASSERT_IF(wrapped.kind != CrossCompartmentKey::StringWrapper, wrapper.isObject());
|
||||
// todo: uncomment when bug 815999 is fixed:
|
||||
// JS_ASSERT(!wrapped.wrapped->isMarked(gc::GRAY));
|
||||
return crossCompartmentWrappers.put(wrapped, wrapper);
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::wrap(JSContext *cx, Value *vp, JSObject *existing)
|
||||
{
|
||||
@ -337,7 +348,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp, JSObject *existing)
|
||||
if (!wrapped)
|
||||
return false;
|
||||
vp->setString(wrapped);
|
||||
if (!crossCompartmentWrappers.put(orig, *vp))
|
||||
if (!putWrapper(orig, *vp))
|
||||
return false;
|
||||
|
||||
if (str->compartment()->isGCMarking()) {
|
||||
@ -385,7 +396,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp, JSObject *existing)
|
||||
|
||||
vp->setObject(*wrapper);
|
||||
|
||||
if (!crossCompartmentWrappers.put(key, *vp))
|
||||
if (!putWrapper(key, *vp))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -273,7 +273,6 @@ struct JSCompartment : public js::gc::GraphNodeBase
|
||||
return gcState == Finished;
|
||||
}
|
||||
|
||||
|
||||
size_t gcBytes;
|
||||
size_t gcTriggerBytes;
|
||||
size_t gcMaxMallocBytes;
|
||||
@ -297,8 +296,11 @@ struct JSCompartment : public js::gc::GraphNodeBase
|
||||
|
||||
void *data;
|
||||
bool active; // GC flag, whether there are active frames
|
||||
|
||||
private:
|
||||
js::WrapperMap crossCompartmentWrappers;
|
||||
|
||||
public:
|
||||
/*
|
||||
* These flags help us to discover if a compartment that shouldn't be alive
|
||||
* manages to outlive a GC.
|
||||
@ -401,6 +403,20 @@ struct JSCompartment : public js::gc::GraphNodeBase
|
||||
bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
|
||||
bool wrap(JSContext *cx, js::AutoIdVector &props);
|
||||
|
||||
bool putWrapper(const js::CrossCompartmentKey& wrapped, const js::Value& wrapper);
|
||||
|
||||
js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) {
|
||||
return crossCompartmentWrappers.lookup(wrapped);
|
||||
}
|
||||
|
||||
void removeWrapper(js::WrapperMap::Ptr p) {
|
||||
crossCompartmentWrappers.remove(p);
|
||||
}
|
||||
|
||||
struct WrapperEnum : public js::WrapperMap::Enum {
|
||||
WrapperEnum(JSCompartment *c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
|
||||
};
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
void markTypes(JSTracer *trc);
|
||||
void discardJitCode(js::FreeOp *fop, bool discardConstraints);
|
||||
|
@ -580,7 +580,7 @@ js::UnmarkGrayGCThing(void *thing)
|
||||
JS_FRIEND_API(void)
|
||||
js::VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback *callback, void *closure)
|
||||
{
|
||||
for (WrapperMap::Enum e(comp->crossCompartmentWrappers); !e.empty(); e.popFront()) {
|
||||
for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
|
||||
gc::Cell *thing = e.front().key.wrapped;
|
||||
if (thing->isMarked(gc::GRAY))
|
||||
callback(closure, thing);
|
||||
|
@ -2489,7 +2489,7 @@ InCrossCompartmentMap(JSObject *src, Cell *dst, JSGCTraceKind dstKind)
|
||||
|
||||
if (dstKind == JSTRACE_OBJECT) {
|
||||
Value key = ObjectValue(*static_cast<JSObject *>(dst));
|
||||
if (WrapperMap::Ptr p = srccomp->crossCompartmentWrappers.lookup(key)) {
|
||||
if (WrapperMap::Ptr p = srccomp->lookupWrapper(key)) {
|
||||
if (*p->value.unsafeGet() == ObjectValue(*src))
|
||||
return true;
|
||||
}
|
||||
@ -2499,7 +2499,7 @@ InCrossCompartmentMap(JSObject *src, Cell *dst, JSGCTraceKind dstKind)
|
||||
* 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()) {
|
||||
for (JSCompartment::WrapperEnum e(srccomp); !e.empty(); e.popFront()) {
|
||||
if (e.front().key.wrapped == dst && ToMarkable(e.front().value) == src)
|
||||
return true;
|
||||
}
|
||||
@ -2676,7 +2676,7 @@ BeginMarkPhase(JSRuntime *rt)
|
||||
|
||||
/* Set the maybeAlive flag based on cross-compartment edges. */
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (WrapperMap::Enum e(c->crossCompartmentWrappers); !e.empty(); e.popFront()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
Cell *dst = e.front().key.wrapped;
|
||||
dst->compartment()->maybeAlive = true;
|
||||
}
|
||||
@ -2876,7 +2876,7 @@ DropStringWrappers(JSRuntime *rt)
|
||||
* compartment group.
|
||||
*/
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (WrapperMap::Enum e(c->crossCompartmentWrappers); !e.empty(); e.popFront()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
if (e.front().key.kind == CrossCompartmentKey::StringWrapper)
|
||||
e.removeFront();
|
||||
}
|
||||
@ -3381,7 +3381,7 @@ BeginSweepPhase(JSRuntime *rt)
|
||||
JS_ASSERT(!rt->gcCompartmentGroup);
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
JS_ASSERT(!c->gcIncomingGrayPointers);
|
||||
for (WrapperMap::Enum e(c->crossCompartmentWrappers); !e.empty(); e.popFront()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
if (e.front().key.kind != CrossCompartmentKey::StringWrapper)
|
||||
AssertNotOnGrayList(&e.front().value.get().toObject());
|
||||
}
|
||||
@ -3550,7 +3550,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
|
||||
JS_ASSERT(!c->gcIncomingGrayPointers);
|
||||
JS_ASSERT(!c->gcLiveArrayBuffers);
|
||||
|
||||
for (WrapperMap::Enum e(c->crossCompartmentWrappers); !e.empty(); e.popFront()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
if (e.front().key.kind != CrossCompartmentKey::StringWrapper)
|
||||
AssertNotOnGrayList(&e.front().value.get().toObject());
|
||||
}
|
||||
|
@ -2834,7 +2834,7 @@ proxy_TraceObject(JSTracer *trc, RawObject obj)
|
||||
* the invariant that the wrapped object is the key in the wrapper map.
|
||||
*/
|
||||
Value key = ObjectValue(*referent);
|
||||
WrapperMap::Ptr p = obj->compartment()->crossCompartmentWrappers.lookup(key);
|
||||
WrapperMap::Ptr p = obj->compartment()->lookupWrapper(key);
|
||||
JS_ASSERT(*p->value.unsafeGet() == ObjectValue(*obj));
|
||||
}
|
||||
}
|
||||
|
@ -1037,8 +1037,7 @@ js::NukeCrossCompartmentWrappers(JSContext* cx,
|
||||
continue;
|
||||
|
||||
// Iterate the wrappers looking for anything interesting.
|
||||
WrapperMap &pmap = c->crossCompartmentWrappers;
|
||||
for (WrapperMap::Enum e(pmap); !e.empty(); e.popFront()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
// Some cross-compartment wrappers are for strings. We're not
|
||||
// interested in those.
|
||||
const CrossCompartmentKey &k = e.front().key;
|
||||
@ -1075,17 +1074,18 @@ js::RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget)
|
||||
JS_ASSERT(origTarget);
|
||||
Value origv = ObjectValue(*origTarget);
|
||||
JSCompartment *wcompartment = wobj->compartment();
|
||||
WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
|
||||
|
||||
// If we're mapping to a different target (as opposed to just recomputing
|
||||
// for the same target), we must not have an existing wrapper for the new
|
||||
// target, otherwise this will break.
|
||||
JS_ASSERT_IF(origTarget != newTarget, !pmap.has(ObjectValue(*newTarget)));
|
||||
JS_ASSERT_IF(origTarget != newTarget,
|
||||
!wcompartment->lookupWrapper(ObjectValue(*newTarget)));
|
||||
|
||||
// The old value should still be in the cross-compartment wrapper map, and
|
||||
// the lookup should return wobj.
|
||||
JS_ASSERT(&pmap.lookup(origv)->value.unsafeGet()->toObject() == wobj);
|
||||
pmap.remove(origv);
|
||||
WrapperMap::Ptr p = wcompartment->lookupWrapper(origv);
|
||||
JS_ASSERT(&p->value.unsafeGet()->toObject() == wobj);
|
||||
wcompartment->removeWrapper(p);
|
||||
|
||||
// When we remove origv from the wrapper map, its wrapper, wobj, must
|
||||
// immediately cease to be a cross-compartment wrapper. Neuter it.
|
||||
@ -1117,7 +1117,7 @@ js::RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget)
|
||||
|
||||
// Update the entry in the compartment's wrapper map to point to the old
|
||||
// wrapper, which has now been updated (via reuse or swap).
|
||||
pmap.put(ObjectValue(*newTarget), ObjectValue(*wobj));
|
||||
wcompartment->putWrapper(ObjectValue(*newTarget), ObjectValue(*wobj));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1134,8 +1134,7 @@ js::RemapAllWrappersForObject(JSContext *cx, JSObject *oldTarget,
|
||||
return false;
|
||||
|
||||
for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {
|
||||
WrapperMap &pmap = c->crossCompartmentWrappers;
|
||||
if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
|
||||
if (WrapperMap::Ptr wp = c->lookupWrapper(origv)) {
|
||||
// We found a wrapper. Remember and root it.
|
||||
toTransplant.infallibleAppend(WrapperValue(wp));
|
||||
}
|
||||
@ -1165,8 +1164,7 @@ js::RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
|
||||
continue;
|
||||
|
||||
// Iterate over the wrappers, filtering appropriately.
|
||||
WrapperMap &pmap = c->crossCompartmentWrappers;
|
||||
for (WrapperMap::Enum e(pmap); !e.empty(); e.popFront()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
// Filter out non-objects.
|
||||
const CrossCompartmentKey &k = e.front().key;
|
||||
if (k.kind != CrossCompartmentKey::ObjectWrapper)
|
||||
|
@ -651,7 +651,7 @@ Debugger::wrapEnvironment(JSContext *cx, Handle<Env*> env, Value *rval)
|
||||
}
|
||||
|
||||
CrossCompartmentKey key(CrossCompartmentKey::DebuggerEnvironment, object, env);
|
||||
if (!object->compartment()->crossCompartmentWrappers.put(key, ObjectValue(*envobj))) {
|
||||
if (!object->compartment()->putWrapper(key, ObjectValue(*envobj))) {
|
||||
environments.remove(env);
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
@ -689,7 +689,7 @@ Debugger::wrapDebuggeeValue(JSContext *cx, Value *vp)
|
||||
|
||||
if (obj->compartment() != object->compartment()) {
|
||||
CrossCompartmentKey key(CrossCompartmentKey::DebuggerObject, object, obj);
|
||||
if (!object->compartment()->crossCompartmentWrappers.put(key, ObjectValue(*dobj))) {
|
||||
if (!object->compartment()->putWrapper(key, ObjectValue(*dobj))) {
|
||||
objects.remove(obj);
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
@ -2612,7 +2612,7 @@ Debugger::wrapScript(JSContext *cx, HandleScript script)
|
||||
}
|
||||
|
||||
CrossCompartmentKey key(CrossCompartmentKey::DebuggerScript, object, script);
|
||||
if (!object->compartment()->crossCompartmentWrappers.put(key, ObjectValue(*scriptobj))) {
|
||||
if (!object->compartment()->putWrapper(key, ObjectValue(*scriptobj))) {
|
||||
scripts.remove(script);
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user