diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index c4af6dc83ed..93c7c21389c 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -1095,16 +1095,25 @@ bool js::RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget) { JS_ASSERT(IsCrossCompartmentWrapper(wobj)); + JS_ASSERT(!IsCrossCompartmentWrapper(newTarget)); JSObject *origTarget = Wrapper::wrappedObject(wobj); 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))); + + // The old value should still be in the cross-compartment wrapper map, and + // the lookup should return wobj. + JS_ASSERT(&pmap.lookup(origv)->value.toObject() == wobj); + pmap.remove(origv); + // When we remove origv from the wrapper map, its wrapper, wobj, must // immediately cease to be a cross-compartment wrapper. Neuter it. - JS_ASSERT(pmap.lookup(origv)); - pmap.remove(origv); NukeCrossCompartmentWrapper(wobj); // First, we wrap it in the new compartment. This will return @@ -1121,8 +1130,12 @@ js::RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget) JS_ASSERT(tobj != wobj); if (!wobj->swap(cx, tobj)) return false; - pmap.put(ObjectValue(*newTarget), ObjectValue(*wobj)); + // Before swapping, this wrapper came out of wrap(), which enforces the + // invariant that the wrapper in the map points directly to the key. + JS_ASSERT(Wrapper::wrappedObject(wobj) == newTarget); + + pmap.put(ObjectValue(*newTarget), ObjectValue(*wobj)); return true; }