зеркало из 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;
|
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_PUBLIC_API(JSObject *)
|
||||||
JS_GetGlobalObject(JSContext *cx)
|
JS_GetGlobalObject(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1009,6 +1009,13 @@ JS_WrapValue(JSContext *cx, jsval *vp);
|
||||||
extern JS_PUBLIC_API(JSObject *)
|
extern JS_PUBLIC_API(JSObject *)
|
||||||
JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target);
|
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 *)
|
extern JS_FRIEND_API(JSObject *)
|
||||||
js_TransplantObjectWithWrapper(JSContext *cx,
|
js_TransplantObjectWithWrapper(JSContext *cx,
|
||||||
JSObject *origobj,
|
JSObject *origobj,
|
||||||
|
|
|
@ -1628,9 +1628,38 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
||||||
if(!propertyHolder || !propertyHolder->copyPropertiesFrom(ccx, flat))
|
if(!propertyHolder || !propertyHolder->copyPropertiesFrom(ccx, flat))
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
flat = JS_TransplantObject(ccx, flat, newobj);
|
JSObject *ww = wrapper->GetWrapper();
|
||||||
if(!flat)
|
if(ww)
|
||||||
return NS_ERROR_FAILURE;
|
{
|
||||||
|
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;
|
wrapper->mFlatJSObject = flat;
|
||||||
if(cache)
|
if(cache)
|
||||||
cache->SetWrapper(flat);
|
cache->SetWrapper(flat);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче