Backed out 4 changesets (bug 1136925) for potentially busting m-e10s-dt on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Thu, 26 Feb 2015 23:17:34 -0800
changeset 231148 7c3cc4f11d38fd6adfc585cf06afb3d092471bdc
parent 231147 81589d78bc6fb391417a9b96f76e445d3335a2f2
child 231149 5dac945cae321bf7da54f6ca830d995fd4758906
push id14154
push userryanvm@gmail.com
push dateFri, 27 Feb 2015 18:27:33 +0000
treeherderb2g-inbound@ee5d1f234412 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1136925
milestone39.0a1
backs out331761aaae2288d5188db8801cf5894b92b23cd2
2faa0e91fe230efb7219e3b63b04641d12ee5264
a00f2530c9111f06c43c987e09306cd23ebfb911
d5e658bc07927efca7cf538ca8d6b8430099febd
Backed out 4 changesets (bug 1136925) for potentially busting m-e10s-dt on a CLOSED TREE Backed out changeset 331761aaae22 (bug 1136925) Backed out changeset 2faa0e91fe23 (bug 1136925) Backed out changeset a00f2530c911 (bug 1136925) Backed out changeset d5e658bc0792 (bug 1136925)
dom/base/WindowNamedPropertiesHandler.cpp
dom/base/nsGlobalWindow.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
js/ipc/WrapperOwner.cpp
js/public/Proxy.h
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
js/src/jsapi.h
js/src/jscompartment.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jswrapper.h
js/src/proxy/Proxy.cpp
js/src/proxy/ScriptedDirectProxyHandler.cpp
js/src/proxy/ScriptedIndirectProxyHandler.cpp
js/src/proxy/Wrapper.cpp
js/src/shell/js.cpp
js/src/vm/ProxyObject.cpp
js/src/vm/ProxyObject.h
js/src/vm/ScopeObject.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/WrapperFactory.h
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -275,13 +275,14 @@ WindowNamedPropertiesHandler::Create(JSC
   // chain, it needs a singleton type to avoid polluting type information
   // for properties on the window.
   JS::Rooted<JSObject*> gsp(aCx);
   js::ProxyOptions options;
   options.setSingleton(true);
   options.setClass(&WindowNamedPropertiesClass.mBase);
   return js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
                             JS::NullHandleValue, aProto,
+                            js::GetGlobalForObjectCrossCompartment(aProto),
                             options);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1052,25 +1052,23 @@ nsChromeOuterWindowProxy::className(JSCo
 
     return "ChromeWindow";
 }
 
 const nsChromeOuterWindowProxy
 nsChromeOuterWindowProxy::singleton;
 
 static JSObject*
-NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> global, bool isChrome)
-{
-  JSAutoCompartment ac(cx, global);
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(global) == global);
-
+NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> parent, bool isChrome)
+{
+  JSAutoCompartment ac(cx, parent);
   js::WrapperOptions options;
   options.setClass(&OuterWindowProxyClass);
   options.setSingleton(true);
-  JSObject *obj = js::Wrapper::New(cx, global,
+  JSObject *obj = js::Wrapper::New(cx, parent, parent,
                                    isChrome ? &nsChromeOuterWindowProxy::singleton
                                             : &nsOuterWindowProxy::singleton,
                                    options);
 
   NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
   return obj;
 }
 
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1808,17 +1808,17 @@ ReparentWrapper(JSContext* aCx, JS::Hand
   // return early we must avoid ending up with two reflectors pointing to the
   // same native. Other than that, the objects we create will just go away.
 
   JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx, newParent);
   if (!proto) {
     return NS_ERROR_FAILURE;
   }
 
-  JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto));
+  JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto, newParent));
   if (!newobj) {
     return NS_ERROR_FAILURE;
   }
 
   js::SetReservedOrProxyPrivateSlot(newobj, DOM_OBJECT_SLOT,
                                     js::GetReservedOrProxyPrivateSlot(aObj, DOM_OBJECT_SLOT));
 
   // At this point, both |aObj| and |newobj| point to the same native
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2797,17 +2797,17 @@ public:
                     const DOMProxyHandler* aHandler,
                     JS::Handle<JSObject*> aProto, T* aNative,
                     JS::MutableHandle<JSObject*> aReflector)
   {
     js::ProxyOptions options;
     options.setClass(aClass);
     JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aNative));
     aReflector.set(js::NewProxyObject(aCx, aHandler, proxyPrivateVal, aProto,
-                                      options));
+                                      /* parent= */nullptr, options));
     if (aReflector) {
       mNative = aNative;
       mReflector = aReflector;
     }
   }
 
   void
   CreateObject(JSContext* aCx, const JSClass* aClass,
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -1015,16 +1015,17 @@ WrapperOwner::fromRemoteObjectVariant(JS
         RootedValue v(cx, UndefinedValue());
         // We need to setLazyProto for the getPrototypeOf hook.
         ProxyOptions options;
         options.setLazyProto(true);
         obj = NewProxyObject(cx,
                              &CPOWProxyHandler::singleton,
                              v,
                              nullptr,
+                             junkScope,
                              options);
         if (!obj)
             return nullptr;
 
         if (!cpows_.add(objId, obj))
             return nullptr;
 
         // Incref once we know the decref will be called.
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -576,17 +576,17 @@ class MOZ_STACK_CLASS ProxyOptions {
   private:
     bool singleton_;
     bool lazyProto_;
     const Class *clasp_;
 };
 
 JS_FRIEND_API(JSObject *)
 NewProxyObject(JSContext *cx, const BaseProxyHandler *handler, HandleValue priv,
-               JSObject *proto, const ProxyOptions &options = ProxyOptions());
+               JSObject *proto, JSObject *parent, const ProxyOptions &options = ProxyOptions());
 
 JSObject *
 RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv);
 
 class JS_FRIEND_API(AutoEnterPolicy)
 {
   public:
     typedef BaseProxyHandler::Action Action;
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -39,32 +39,33 @@ static JSObject *
 PreWrap(JSContext *cx, JS::HandleObject scope, JS::HandleObject obj,
         JS::HandleObject objectPassedToWrap)
 {
     JS_GC(JS_GetRuntime(cx));
     return obj;
 }
 
 static JSObject *
-Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj)
+Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj,
+     JS::HandleObject parent)
 {
-    return js::Wrapper::New(cx, obj, &js::CrossCompartmentWrapper::singleton);
+    return js::Wrapper::New(cx, obj, parent, &js::CrossCompartmentWrapper::singleton);
 }
 
 static const JSWrapObjectCallbacks WrapObjectCallbacks = {
     Wrap,
     PreWrap
 };
 
 BEGIN_TEST(testBug604087)
 {
     js::WrapperOptions options;
     options.setClass(&OuterWrapperClass);
     options.setSingleton(true);
-    JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, &js::Wrapper::singleton, options));
+    JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, global, &js::Wrapper::singleton, options));
     JS::RootedObject compartment2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
     JS::RootedObject compartment3(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
     JS::RootedObject compartment4(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
 
     JS::RootedObject c2wrapper(cx, wrap(cx, outerObj, compartment2));
     CHECK(c2wrapper);
     c2wrapper->as<js::ProxyObject>().setExtra(0, js::Int32Value(2));
 
@@ -75,17 +76,17 @@ BEGIN_TEST(testBug604087)
     JS::RootedObject c4wrapper(cx, wrap(cx, outerObj, compartment4));
     CHECK(c4wrapper);
     c4wrapper->as<js::ProxyObject>().setExtra(0, js::Int32Value(4));
     compartment4 = c4wrapper = nullptr;
 
     JS::RootedObject next(cx);
     {
         JSAutoCompartment ac(cx, compartment2);
-        next = js::Wrapper::New(cx, compartment2, &js::Wrapper::singleton, options);
+        next = js::Wrapper::New(cx, compartment2, compartment2, &js::Wrapper::singleton, options);
         CHECK(next);
     }
 
     JS_SetWrapObjectCallbacks(JS_GetRuntime(cx), &WrapObjectCallbacks);
     CHECK(JS_TransplantObject(cx, outerObj, next));
     return true;
 }
 END_TEST(testBug604087)
--- a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
+++ b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
@@ -67,17 +67,17 @@ BEGIN_TEST(testSetPropertyIgnoringNamedG
 {
     RootedValue protov(cx);
     EVAL("Object.prototype", &protov);
 
     RootedValue targetv(cx);
     EVAL("({})", &targetv);
 
     RootedObject proxyObj(cx, NewProxyObject(cx, &customProxyHandler, targetv,
-                                             &protov.toObject(), ProxyOptions()));
+                                             &protov.toObject(), global, ProxyOptions()));
     CHECK(proxyObj);
 
     CHECK(JS_DefineProperty(cx, global, "target", targetv, 0));
     CHECK(JS_DefineProperty(cx, global, "proxy", proxyObj, 0));
 
     RootedValue v(cx);
     EVAL("Object.getOwnPropertyDescriptor(proxy, 'phantom').value", &v);
     CHECK_SAME(v, Int32Value(42));
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -733,17 +733,18 @@ typedef bool
  * that implements the desired prolicy for this kind of object in the
  * destination compartment. |obj| is the object to be wrapped. If |existing| is
  * non-nullptr, it will point to an existing wrapper object that should be
  * re-used if possible. |existing| is guaranteed to be a cross-compartment
  * wrapper with a lazily-defined prototype and the correct global. It is
  * guaranteed not to wrap a function.
  */
 typedef JSObject *
-(* JSWrapObjectCallback)(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj);
+(* JSWrapObjectCallback)(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj,
+                         JS::HandleObject parent);
 
 /*
  * Callback used by the wrap hook to ask the embedding to prepare an object
  * for wrapping in a context. This might include unwrapping other wrappers
  * or even finding a more suitable object for the new compartment.
  */
 typedef JSObject *
 (* JSPreWrapCallback)(JSContext *cx, JS::HandleObject scope, JS::HandleObject obj,
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -438,17 +438,17 @@ JSCompartment::wrap(JSContext *cx, Mutab
             existing->isCallable() ||
             existing->getParent() != global ||
             obj->isCallable())
         {
             existing = nullptr;
         }
     }
 
-    obj.set(cb->wrap(cx, existing, obj));
+    obj.set(cb->wrap(cx, existing, obj, global));
     if (!obj)
         return false;
 
     // We maintain the invariant that the key in the cross-compartment wrapper
     // map is always directly wrapped by the value.
     MOZ_ASSERT(Wrapper::wrappedObject(obj) == &key.get().toObject());
 
     return putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*obj));
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -617,20 +617,20 @@ js::StringToLinearStringSlow(JSContext *
 
 JS_FRIEND_API(void)
 JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
 {
     rt->setTelemetryCallback(rt, callback);
 }
 
 JS_FRIEND_API(JSObject *)
-JS_CloneObject(JSContext *cx, HandleObject obj, HandleObject protoArg)
+JS_CloneObject(JSContext *cx, HandleObject obj, HandleObject protoArg, HandleObject parent)
 {
     Rooted<TaggedProto> proto(cx, TaggedProto(protoArg.get()));
-    return CloneObject(cx, obj, proto);
+    return CloneObject(cx, obj, proto, parent);
 }
 
 #ifdef DEBUG
 JS_FRIEND_API(void)
 js_DumpString(JSString *str)
 {
     str->dump();
 }
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -143,17 +143,18 @@ JS_ScriptHasMutedErrors(JSScript *script
 extern JS_FRIEND_API(JSObject *)
 JS_ObjectToInnerObject(JSContext *cx, JS::HandleObject obj);
 
 /* Requires obj != nullptr. */
 extern JS_FRIEND_API(JSObject *)
 JS_ObjectToOuterObject(JSContext *cx, JS::HandleObject obj);
 
 extern JS_FRIEND_API(JSObject *)
-JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto);
+JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto,
+               JS::HandleObject parent);
 
 /*
  * Copy the own properties of src to dst in a fast way.  src and dst must both
  * be native and must be in the compartment of cx.  They must have the same
  * class, the same parent, and the same prototype.  Class reserved slots will
  * NOT be copied.
  *
  * dst must not have any properties on it before this function is called.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1772,43 +1772,43 @@ CopyProxyObject(JSContext *cx, Handle<Pr
             return false;
         SetProxyExtra(to, n, v);
     }
 
     return true;
 }
 
 JSObject *
-js::CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto)
+js::CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent)
 {
     if (!obj->isNative() && !obj->is<ProxyObject>()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                              JSMSG_CANT_CLONE_OBJECT);
         return nullptr;
     }
 
     RootedObject clone(cx);
     if (obj->isNative()) {
-        clone = NewObjectWithGivenTaggedProto(cx, obj->getClass(), proto, NullPtr());
+        clone = NewObjectWithGivenTaggedProto(cx, obj->getClass(), proto, parent);
         if (!clone)
             return nullptr;
 
         if (clone->is<JSFunction>() && (obj->compartment() != clone->compartment())) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                                  JSMSG_CANT_CLONE_OBJECT);
             return nullptr;
         }
 
         if (obj->as<NativeObject>().hasPrivate())
             clone->as<NativeObject>().setPrivate(obj->as<NativeObject>().getPrivate());
     } else {
         ProxyOptions options;
         options.setClass(obj->getClass());
 
-        clone = ProxyObject::New(cx, GetProxyHandler(obj), JS::NullHandleValue, proto, options);
+        clone = ProxyObject::New(cx, GetProxyHandler(obj), JS::NullHandleValue, proto, parent, options);
         if (!clone)
             return nullptr;
 
         if (!CopyProxyObject(cx, obj.as<ProxyObject>(), clone.as<ProxyObject>()))
             return nullptr;
     }
 
     return clone;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1132,17 +1132,17 @@ CreateThisForFunctionWithProto(JSContext
 extern JSObject *
 CreateThisForFunction(JSContext *cx, js::HandleObject callee, NewObjectKind newKind);
 
 // Generic call for constructing |this|.
 extern JSObject *
 CreateThis(JSContext *cx, const js::Class *clasp, js::HandleObject callee);
 
 extern JSObject *
-CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto);
+CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent);
 
 extern NativeObject *
 DeepCloneObjectLiteral(JSContext *cx, HandleNativeObject obj, NewObjectKind newKind = GenericObject);
 
 extern bool
 DefineProperties(JSContext *cx, HandleObject obj, HandleObject props);
 
 /*
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -64,17 +64,17 @@ class JS_FRIEND_API(Wrapper) : public Di
     enum Flags {
         CROSS_COMPARTMENT = 1 << 0,
         LAST_USED_FLAG = CROSS_COMPARTMENT
     };
 
     virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
                               MutableHandleValue vp) const MOZ_OVERRIDE;
 
-    static JSObject *New(JSContext *cx, JSObject *obj, const Wrapper *handler,
+    static JSObject *New(JSContext *cx, JSObject *obj, JSObject *parent, const Wrapper *handler,
                          const WrapperOptions &options = WrapperOptions());
 
     static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, const Wrapper *handler);
 
     static const Wrapper *wrapperHandler(JSObject *wrapper);
 
     static JSObject *wrappedObject(JSObject *wrapper);
 
@@ -212,17 +212,18 @@ class JS_FRIEND_API(SecurityWrapper) : p
     typedef Base Permissive;
     typedef SecurityWrapper<Base> Restrictive;
 };
 
 typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
 typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
 
 extern JSObject *
-TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj);
+TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
+                         HandleObject parent);
 
 inline bool
 IsWrapper(JSObject *obj)
 {
     return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
 }
 
 // Given a JSObject, returns that object stripped of wrappers. If
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -723,24 +723,25 @@ js::proxy_GetElements(JSContext *cx, Han
 
 const Class js::ProxyObject::class_ =
     PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy));
 
 const Class* const js::ProxyClassPtr = &js::ProxyObject::class_;
 
 JS_FRIEND_API(JSObject *)
 js::NewProxyObject(JSContext *cx, const BaseProxyHandler *handler, HandleValue priv, JSObject *proto_,
-                   const ProxyOptions &options)
+                   JSObject *parent_, const ProxyOptions &options)
 {
     if (options.lazyProto()) {
         MOZ_ASSERT(!proto_);
         proto_ = TaggedProto::LazyProto;
     }
 
-    return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), options);
+    return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), parent_,
+                            options);
 }
 
 void
 ProxyObject::renew(JSContext *cx, const BaseProxyHandler *handler, Value priv)
 {
     MOZ_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this));
     MOZ_ASSERT(getParent() == cx->global());
     MOZ_ASSERT(getClass() == &ProxyObject::class_);
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -1201,17 +1201,17 @@ NewScriptedProxy(JSContext *cx, CallArgs
     if (!target)
         return false;
     RootedObject handler(cx, NonNullObject(cx, args[1]));
     if (!handler)
         return false;
     RootedValue priv(cx, ObjectValue(*target));
     JSObject *proxy_ =
         NewProxyObject(cx, &ScriptedDirectProxyHandler::singleton,
-                       priv, TaggedProto::LazyProto);
+                       priv, TaggedProto::LazyProto, cx->global());
     if (!proxy_)
         return false;
     Rooted<ProxyObject*> proxy(cx, &proxy_->as<ProxyObject>());
     proxy->setExtra(ScriptedDirectProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
 
     // Assign [[Call]] and [[Construct]]
     uint32_t callable = target->isCallable() ? ScriptedDirectProxyHandler::IS_CALLABLE : 0;
     uint32_t constructor = target->isConstructor() ? ScriptedDirectProxyHandler::IS_CONSTRUCTOR : 0;
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -401,26 +401,29 @@ js::proxy_create(JSContext *cx, unsigned
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "create", "0", "s");
         return false;
     }
     JSObject *handler = NonNullObject(cx, args[0]);
     if (!handler)
         return false;
-    JSObject *proto;
+    JSObject *proto, *parent = nullptr;
     if (args.get(1).isObject()) {
         proto = &args[1].toObject();
+        parent = proto->getParent();
     } else {
         MOZ_ASSERT(IsFunctionObject(&args.callee()));
         proto = nullptr;
     }
+    if (!parent)
+        parent = args.callee().getParent();
     RootedValue priv(cx, ObjectValue(*handler));
     JSObject *proxy = NewProxyObject(cx, &ScriptedIndirectProxyHandler::singleton,
-                                     priv, proto);
+                                     priv, proto, parent);
     if (!proxy)
         return false;
 
     args.rval().setObject(*proxy);
     return true;
 }
 
 bool
@@ -430,19 +433,22 @@ js::proxy_createFunction(JSContext *cx, 
     if (args.length() < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "createFunction", "1", "");
         return false;
     }
     RootedObject handler(cx, NonNullObject(cx, args[0]));
     if (!handler)
         return false;
-    RootedObject proto(cx, args.callee().global().getOrCreateFunctionPrototype(cx));
+    RootedObject proto(cx), parent(cx);
+    parent = args.callee().getParent();
+    proto = parent->global().getOrCreateFunctionPrototype(cx);
     if (!proto)
         return false;
+    parent = proto->getParent();
 
     RootedObject call(cx, ValueToCallable(cx, args[1], args.length() - 2));
     if (!call)
         return false;
     RootedObject construct(cx, nullptr);
     if (args.length() > 2) {
         construct = ValueToCallable(cx, args[2], args.length() - 3);
         if (!construct)
@@ -458,16 +464,16 @@ js::proxy_createFunction(JSContext *cx, 
     if (!ccHolder)
         return false;
     ccHolder->as<NativeObject>().setReservedSlot(0, ObjectValue(*call));
     ccHolder->as<NativeObject>().setReservedSlot(1, ObjectValue(*construct));
 
     RootedValue priv(cx, ObjectValue(*handler));
     JSObject *proxy =
         NewProxyObject(cx, &CallableScriptedIndirectProxyHandler::singleton,
-                       priv, proto);
+                       priv, proto, parent);
     if (!proxy)
         return false;
     proxy->as<ProxyObject>().setExtra(0, ObjectValue(*ccHolder));
 
     args.rval().setObject(*proxy);
     return true;
 }
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -28,21 +28,23 @@ Wrapper::defaultValue(JSContext *cx, Han
 {
     vp.set(ObjectValue(*proxy->as<ProxyObject>().target()));
     if (hint == JSTYPE_VOID)
         return ToPrimitive(cx, vp);
     return ToPrimitive(cx, hint, vp);
 }
 
 JSObject *
-Wrapper::New(JSContext *cx, JSObject *obj, const Wrapper *handler,
+Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, const Wrapper *handler,
              const WrapperOptions &options)
 {
+    MOZ_ASSERT(parent);
+
     RootedValue priv(cx, ObjectValue(*obj));
-    return NewProxyObject(cx, handler, priv, options.proto(), options);
+    return NewProxyObject(cx, handler, priv, options.proto(), parent, options);
 }
 
 JSObject *
 Wrapper::Renew(JSContext *cx, JSObject *existing, JSObject *obj, const Wrapper *handler)
 {
     existing->as<ProxyObject>().renew(cx, handler, ObjectValue(*obj));
     return existing;
 }
@@ -120,21 +122,22 @@ js::UnwrapOneChecked(JSObject *obj, bool
 const char Wrapper::family = 0;
 const Wrapper Wrapper::singleton((unsigned)0);
 const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
 JSObject *Wrapper::defaultProto = TaggedProto::LazyProto;
 
 /* Compartments. */
 
 extern JSObject *
-js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj)
+js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
+                             HandleObject parent)
 {
     // Allow wrapping outer window proxies.
     MOZ_ASSERT(!obj->is<WrapperObject>() || obj->getClass()->ext.innerObject);
-    return Wrapper::New(cx, obj, &CrossCompartmentWrapper::singleton);
+    return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton);
 }
 
 ErrorCopier::~ErrorCopier()
 {
     JSContext *cx = ac->context()->asJSContext();
     if (ac->origin() != cx->compartment() && cx->isExceptionPending()) {
         RootedValue exc(cx);
         if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3963,17 +3963,17 @@ WrapWithProto(JSContext *cx, unsigned ar
     if (!obj.isObject() || !proto.isObjectOrNull()) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS,
                              "wrapWithProto");
         return false;
     }
 
     WrapperOptions options(cx);
     options.setProto(proto.toObjectOrNull());
-    JSObject *wrapped = Wrapper::New(cx, &obj.toObject(),
+    JSObject *wrapped = Wrapper::New(cx, &obj.toObject(), &obj.toObject().global(),
                                      &Wrapper::singletonWithPrototype, options);
     if (!wrapped)
         return false;
 
     args.rval().setObject(*wrapped);
     return true;
 }
 
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -9,24 +9,26 @@
 #include "jscompartment.h"
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 
 /* static */ ProxyObject *
 ProxyObject::New(JSContext *cx, const BaseProxyHandler *handler, HandleValue priv, TaggedProto proto_,
-                 const ProxyOptions &options)
+                 JSObject *parent_, const ProxyOptions &options)
 {
     Rooted<TaggedProto> proto(cx, proto_);
+    RootedObject parent(cx, parent_);
 
     const Class *clasp = options.clasp();
 
     MOZ_ASSERT(isValidProxyClass(clasp));
     MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
+    MOZ_ASSERT_IF(parent, cx->compartment() == parent->compartment());
 
     /*
      * Eagerly mark properties unknown for proxies, so we don't try to track
      * their properties and so that we don't need to walk the compartment if
      * their prototype changes later.  But don't do this for DOM proxies,
      * because we want to be able to keep track of them in typesets in useful
      * ways.
      */
@@ -43,17 +45,17 @@ ProxyObject::New(JSContext *cx, const Ba
         allocKind = GetBackgroundAllocKind(allocKind);
 
     ProxyValueArray *values = cx->zone()->new_<ProxyValueArray>();
     if (!values)
         return nullptr;
 
     // Note: this will initialize the object's |data| to strange values, but we
     // will immediately overwrite those below.
-    RootedObject obj(cx, NewObjectWithGivenTaggedProto(cx, clasp, proto, NullPtr(), allocKind,
+    RootedObject obj(cx, NewObjectWithGivenTaggedProto(cx, clasp, proto, parent, allocKind,
                                                        newKind));
     if (!obj) {
         js_free(values);
         return nullptr;
     }
 
     Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
 
--- a/js/src/vm/ProxyObject.h
+++ b/js/src/vm/ProxyObject.h
@@ -23,17 +23,18 @@ class ProxyObject : public JSObject
         static_assert(sizeof(ProxyObject) == sizeof(JSObject_Slots0),
                       "proxy object size must match GC thing size");
         static_assert(offsetof(ProxyObject, data) == ProxyDataOffset,
                       "proxy object layout must match shadow interface");
     }
 
   public:
     static ProxyObject *New(JSContext *cx, const BaseProxyHandler *handler, HandleValue priv,
-                            TaggedProto proto_, const ProxyOptions &options);
+                            TaggedProto proto_, JSObject *parent_,
+                            const ProxyOptions &options);
 
     const Value &private_() {
         return GetProxyPrivate(this);
     }
 
     void setCrossCompartmentPrivate(const Value &priv);
     void setSameCompartmentPrivate(const Value &priv);
 
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1731,17 +1731,17 @@ const char DebugScopeProxy::family = 0;
 const DebugScopeProxy DebugScopeProxy::singleton;
 
 /* static */ DebugScopeObject *
 DebugScopeObject::create(JSContext *cx, ScopeObject &scope, HandleObject enclosing)
 {
     MOZ_ASSERT(scope.compartment() == cx->compartment());
     RootedValue priv(cx, ObjectValue(scope));
     JSObject *obj = NewProxyObject(cx, &DebugScopeProxy::singleton, priv,
-                                   nullptr /* proto */);
+                                   nullptr /* proto */, &scope.global());
     if (!obj)
         return nullptr;
 
     MOZ_ASSERT(!enclosing->is<ScopeObject>());
 
     DebugScopeObject *debugScope = &obj->as<DebugScopeObject>();
     debugScope->setExtra(ENCLOSING_EXTRA, ObjectValue(*enclosing));
     debugScope->setExtra(SNAPSHOT_EXTRA, NullValue());
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -642,17 +642,17 @@ WrapCallable(JSContext *cx, HandleObject
     // callable as the private.  We put the given sandboxProtoProxy in
     // an extra slot, and our call() hook depends on that.
     MOZ_ASSERT(js::IsProxy(sandboxProtoProxy) &&
                js::GetProxyHandler(sandboxProtoProxy) ==
                  &xpc::sandboxProxyHandler);
 
     RootedValue priv(cx, ObjectValue(*callable));
     JSObject *obj = js::NewProxyObject(cx, &xpc::sandboxCallableProxyHandler,
-                                       priv, nullptr);
+                                       priv, nullptr, nullptr);
     if (obj) {
         js::SetProxyExtra(obj, SandboxCallableProxyHandler::SandboxProxySlot,
                           ObjectValue(*sandboxProtoProxy));
     }
 
     return obj;
 }
 
@@ -967,17 +967,17 @@ xpc::CreateSandboxObject(JSContext *cx, 
             JSObject *unwrappedProto = js::UncheckedUnwrap(options.proto, false);
             const js::Class *unwrappedClass = js::GetObjectClass(unwrappedProto);
             if (IS_WN_CLASS(unwrappedClass) ||
                 mozilla::dom::IsDOMClass(Jsvalify(unwrappedClass))) {
                 // Wrap it up in a proxy that will do the right thing in terms
                 // of this-binding for methods.
                 RootedValue priv(cx, ObjectValue(*options.proto));
                 options.proto = js::NewProxyObject(cx, &xpc::sandboxProxyHandler,
-                                                   priv, nullptr);
+                                                   priv, nullptr, nullptr);
                 if (!options.proto)
                     return NS_ERROR_OUT_OF_MEMORY;
             }
 
             ok = JS_SetPrototype(cx, sandbox, options.proto);
             if (!ok)
                 return NS_ERROR_XPC_UNEXPECTED;
         }
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -73,17 +73,19 @@ JSObject *
 WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
 {
     // The caller is required to have already done a lookup.
     // NB: This implictly performs the assertions of GetXrayWaiver.
     MOZ_ASSERT(!GetXrayWaiver(obj));
     XPCWrappedNativeScope *scope = ObjectScope(obj);
 
     JSAutoCompartment ac(cx, obj);
-    JSObject *waiver = Wrapper::New(cx, obj, &XrayWaiver);
+    JSObject *waiver = Wrapper::New(cx, obj,
+                                    JS_GetGlobalForObject(cx, obj),
+                                    &XrayWaiver);
     if (!waiver)
         return nullptr;
 
     // Add the new waiver to the map. It's important that we only ever have
     // one waiver for the lifetime of the target object.
     if (!scope->mWaiverWrapperMap) {
         scope->mWaiverWrapperMap =
           JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_LENGTH);
@@ -375,17 +377,18 @@ SelectAddonWrapper(JSContext *cx, Handle
     else if (wrapper == &PermissiveXrayDOM::singleton)
         return &AddonWrapper<PermissiveXrayDOM>::singleton;
 
     // |wrapper| is not supported for interposition, so we don't do it.
     return wrapper;
 }
 
 JSObject *
-WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj)
+WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
+                       HandleObject parent)
 {
     MOZ_ASSERT(!IsWrapper(obj) ||
                GetProxyHandler(obj) == &XrayWaiver ||
                js::GetObjectClass(obj)->ext.innerObject,
                "wrapped object passed to rewrap");
     MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(JS_GetClass(obj)), "trying to wrap a holder");
     MOZ_ASSERT(!js::IsInnerObject(obj));
     // We sometimes end up here after nsContentUtils has been shut down but before
@@ -496,17 +499,17 @@ WrapperFactory::Rewrap(JSContext *cx, Ha
         }
     }
 
     DEBUG_CheckUnwrapSafety(obj, wrapper, origin, target);
 
     if (existing)
         return Wrapper::Renew(cx, existing, obj, wrapper);
 
-    return Wrapper::New(cx, obj, wrapper);
+    return Wrapper::New(cx, obj, parent, wrapper);
 }
 
 // Call WaiveXrayAndWrap when you have a JS object that you don't want to be
 // wrapped in an Xray wrapper. cx->compartment is the compartment that will be
 // using the returned object. If the object to be wrapped is already in the
 // correct compartment, then this returns the unwrapped object.
 bool
 WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleValue vp)
--- a/js/xpconnect/wrappers/WrapperFactory.h
+++ b/js/xpconnect/wrappers/WrapperFactory.h
@@ -41,17 +41,18 @@ class WrapperFactory {
     static JSObject *PrepareForWrapping(JSContext *cx,
                                         JS::HandleObject scope,
                                         JS::HandleObject obj,
                                         JS::HandleObject objectPassedToWrap);
 
     // Rewrap an object that is about to cross compartment boundaries.
     static JSObject *Rewrap(JSContext *cx,
                             JS::HandleObject existing,
-                            JS::HandleObject obj);
+                            JS::HandleObject obj,
+                            JS::HandleObject parent);
 
     // Wrap wrapped object into a waiver wrapper and then re-wrap it.
     static bool WaiveXrayAndWrap(JSContext *cx, JS::MutableHandleValue vp);
     static bool WaiveXrayAndWrap(JSContext *cx, JS::MutableHandleObject object);
 };
 
 extern const js::Wrapper XrayWaiver;