зеркало из https://github.com/mozilla/pjs.git
Fixing bug 623810. r=jst@mozilla.org, gal@uci.edu, a=blocker. CLOSED TREE
This commit is contained in:
Родитель
caad5989c1
Коммит
0857373fac
|
@ -1369,6 +1369,103 @@ JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
|
|||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* The location object is special. There is the location object itself and
|
||||
* then the location object wrapper. Because there are no direct references to
|
||||
* the location object itself, we don't want the old obj (|origobj| here) to
|
||||
* become the new wrapper but the wrapper itself instead. This leads to very
|
||||
* subtle differences between js_TransplantObjectWithWrapper and
|
||||
* JS_TransplantObject.
|
||||
*/
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
JSObject *origobj,
|
||||
JSObject *origwrapper,
|
||||
JSObject *targetobj,
|
||||
JSObject *targetwrapper)
|
||||
{
|
||||
JSObject *obj;
|
||||
JSCompartment *destination = targetobj->getCompartment();
|
||||
WrapperMap &map = destination->crossCompartmentWrappers;
|
||||
|
||||
// |origv| is the map entry we're looking up. The map entries are going to
|
||||
// be for the location object itself.
|
||||
Value origv = ObjectValue(*origobj);
|
||||
|
||||
// There might already be a wrapper for the original object in the new
|
||||
// compartment.
|
||||
if (WrapperMap::Ptr p = map.lookup(origv)) {
|
||||
// There is. Make the existing wrapper a same compartment location
|
||||
// wrapper (swapping it with the given new wrapper).
|
||||
obj = &p->value.toObject();
|
||||
map.remove(p);
|
||||
if (!obj->swap(cx, targetwrapper))
|
||||
return NULL;
|
||||
} else {
|
||||
// Otherwise, use the passed-in wrapper as the same compartment
|
||||
// location wrapper.
|
||||
obj = targetwrapper;
|
||||
}
|
||||
|
||||
// Now, iterate through other scopes looking for references to the old
|
||||
// location object. Note that the entries in the maps are for |origobj|
|
||||
// and not |origwrapper|. They need to be updated to point at the new
|
||||
// location object.
|
||||
Value targetv = ObjectValue(*targetobj);
|
||||
WrapperVector &vector = cx->runtime->compartments;
|
||||
AutoValueVector toTransplant(cx);
|
||||
toTransplant.reserve(vector.length());
|
||||
|
||||
for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
|
||||
WrapperMap &pmap = (*p)->crossCompartmentWrappers;
|
||||
if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
|
||||
// We found a wrapper. Remember and root it.
|
||||
toTransplant.append(wp->value);
|
||||
}
|
||||
}
|
||||
|
||||
for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
|
||||
JSObject *wobj = &begin->toObject();
|
||||
JSCompartment *wcompartment = wobj->compartment();
|
||||
WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
|
||||
JS_ASSERT(pmap.lookup(origv));
|
||||
pmap.remove(origv);
|
||||
|
||||
// First, we wrap it in the new compartment. This will return a
|
||||
// new wrapper.
|
||||
AutoCompartment ac(cx, wobj);
|
||||
|
||||
JSObject *tobj = targetobj;
|
||||
if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
|
||||
return NULL;
|
||||
|
||||
// Now, because we need to maintain object identity, we do a brain
|
||||
// transplant on the old object. At the same time, we update the
|
||||
// entry in the compartment's wrapper map to point to the old
|
||||
// wrapper.
|
||||
JS_ASSERT(tobj != wobj);
|
||||
if (!wobj->swap(cx, tobj))
|
||||
return NULL;
|
||||
pmap.put(targetv, ObjectValue(*wobj));
|
||||
}
|
||||
|
||||
// Lastly, update the original object to point to the new one. However, as
|
||||
// mentioned above, we do the transplant on the wrapper, not the object
|
||||
// itself, since all of the references are to the object itself.
|
||||
{
|
||||
AutoCompartment ac(cx, origobj);
|
||||
JSObject *tobj = obj;
|
||||
if (!ac.enter() || !JS_WrapObject(cx, &tobj))
|
||||
return NULL;
|
||||
if (!origwrapper->swap(cx, tobj))
|
||||
return NULL;
|
||||
origwrapper->getCompartment()->crossCompartmentWrappers.put(targetv,
|
||||
ObjectValue(*origwrapper));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_GetGlobalObject(JSContext *cx)
|
||||
{
|
||||
|
|
|
@ -1009,6 +1009,13 @@ JS_WrapValue(JSContext *cx, jsval *vp);
|
|||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
JSObject *origobj,
|
||||
JSObject *origwrapper,
|
||||
JSObject *targetobj,
|
||||
JSObject *targetwrapper);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
JSObject *origobj,
|
||||
|
|
|
@ -1628,9 +1628,38 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
|||
if(!propertyHolder || !propertyHolder->copyPropertiesFrom(ccx, flat))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
flat = JS_TransplantObject(ccx, flat, newobj);
|
||||
if(!flat)
|
||||
return NS_ERROR_FAILURE;
|
||||
JSObject *ww = wrapper->GetWrapper();
|
||||
if(ww)
|
||||
{
|
||||
JSObject *newwrapper;
|
||||
if(xpc::WrapperFactory::IsLocationObject(flat))
|
||||
{
|
||||
newwrapper = xpc::WrapperFactory::WrapLocationObject(ccx, newobj);
|
||||
if(!newwrapper)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(wrapper->NeedsSOW(), "weird wrapper wrapper");
|
||||
newwrapper = xpc::WrapperFactory::WrapSOWObject(ccx, newobj);
|
||||
if(!newwrapper)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ww = js_TransplantObjectWithWrapper(ccx, flat, ww, newobj,
|
||||
newwrapper);
|
||||
if(!ww)
|
||||
return NS_ERROR_FAILURE;
|
||||
flat = newobj;
|
||||
wrapper->SetWrapper(ww);
|
||||
}
|
||||
else
|
||||
{
|
||||
flat = JS_TransplantObject(ccx, flat, newobj);
|
||||
if(!flat)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
wrapper->mFlatJSObject = flat;
|
||||
if(cache)
|
||||
cache->SetWrapper(flat);
|
||||
|
|
Загрузка…
Ссылка в новой задаче