diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 1d0971af30be..7f8e89dcb00d 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -2259,19 +2259,10 @@ ReparentWrapper(JSContext* aCx, JS::Handle aObjArg, ErrorResult& aErr propertyHolder = nullptr; } - // Expandos from other compartments are attached to the target JS object. - // Copy them over, and let the old ones die a natural death. - - // Note that at this point the DOM_OBJECT_SLOT for |newobj| has not been set. - // CloneExpandoChain() will use this property of |newobj| when it calls - // preserveWrapper() via attachExpandoObject() if |aObj| has expandos set, and - // preserveWrapper() will not do anything in this case. This is safe because - // if expandos are present then the wrapper will already have been preserved - // for this native. - if (!xpc::XrayUtils::CloneExpandoChain(aCx, newobj, aObj)) { - aError.StealExceptionFromJSContext(aCx); - return; - } + // Grab a reference to the chain of objects that carry aObj's Xray expando + // properties (from all compartments). Transplanting will blow this away; + // we'll restore it manually afterwards. + JS::Rooted expandoChain(aCx, xpc::XrayUtils::GetExpandoChain(aObj)); // We've set up |newobj|, so we make it own the native by setting its reserved // slot and nulling out the reserved slot of |obj|. @@ -2288,6 +2279,14 @@ ReparentWrapper(JSContext* aCx, JS::Handle aObjArg, ErrorResult& aErr MOZ_CRASH(); } + // Copy Xray expando properties to the new wrapper. + if (!xpc::XrayUtils::CloneExpandoChain(aCx, aObj, expandoChain)) { + // Failure here means some expandos were not copied over. The object graph + // and the Xray machinery are left in a consistent state, but mysteriously + // losing these expandos is too weird to allow. + MOZ_CRASH(); + } + nsWrapperCache* cache = nullptr; CallQueryInterface(native, &cache); bool preserving = cache->PreservingWrapper(); diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 6fdb70bdfaa5..c71ee6ea289c 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -1241,30 +1241,12 @@ XrayTraits::ensureExpandoObject(JSContext* cx, HandleObject wrapper, } bool -XrayTraits::cloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject src) +XrayTraits::cloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject srcChain) { MOZ_ASSERT(js::IsObjectInContextCompartment(dst, cx)); MOZ_ASSERT(getExpandoChain(dst) == nullptr); - RootedObject oldHead(cx, getExpandoChain(src)); - -#ifdef DEBUG - // When this is called from dom::ReparentWrapper() there will be no native - // set for |dst|. Eventually it will be set to that of |src|. This will - // prevent attachExpandoObject() from preserving the wrapper, but this is - // not a problem because in this case the wrapper will already have been - // preserved when expandos were originally added to |src|. Assert the - // wrapper for |src| has been preserved if it has expandos set. - if (oldHead) { - nsISupports* identity = mozilla::dom::UnwrapDOMObjectToISupports(src); - if (identity) { - nsWrapperCache* cache = nullptr; - CallQueryInterface(identity, &cache); - MOZ_ASSERT_IF(cache, cache->PreservingWrapper()); - } - } -#endif - + RootedObject oldHead(cx, srcChain); while (oldHead) { RootedObject exclusive(cx, JS_GetReservedSlot(oldHead, JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL) @@ -1318,11 +1300,14 @@ XrayTraits::getExpandoClass(JSContext* cx, HandleObject target) const } namespace XrayUtils { -bool CloneExpandoChain(JSContext* cx, JSObject* dstArg, JSObject* srcArg) +JSObject* GetExpandoChain(HandleObject target) { - RootedObject dst(cx, dstArg); - RootedObject src(cx, srcArg); - return GetXrayTraits(src)->cloneExpandoChain(cx, dst, src); + return GetXrayTraits(target)->getExpandoChain(target); +} + +bool CloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject srcChain) +{ + return GetXrayTraits(dst)->cloneExpandoChain(cx, dst, srcChain); } } // namespace XrayUtils diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index a41ef762cfb3..db6779c752af 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -35,9 +35,14 @@ namespace xpc { namespace XrayUtils { -bool IsXPCWNHolderClass(const JSClass* clasp); +bool +IsXPCWNHolderClass(const JSClass* clasp); -bool CloneExpandoChain(JSContext* cx, JSObject* src, JSObject* dst); +JSObject* +GetExpandoChain(JS::HandleObject target); + +bool +CloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject srcChain); bool IsTransparent(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id); @@ -114,7 +119,7 @@ public: JSObject* getExpandoChain(JS::HandleObject obj); bool setExpandoChain(JSContext* cx, JS::HandleObject obj, JS::HandleObject chain); - bool cloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject src); + bool cloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject srcChain); protected: static const JSClass HolderClass;