Bug 825392 - Infer the global from the reflector in DoInitJSClass. r=bz
authorBobby Holley <bobbyholley@gmail.com>
Wed, 19 Mar 2014 13:35:45 -0300
changeset 186360 7462463054e3146815c1aba1ee7e2e823a3629ef
parent 186359 8d63685f59f01f36d1b57577020b2e2dc5f21269
child 186361 3626a613190ec9570f760a81ff3a3f6fe3061a30
push idunknown
push userunknown
push dateunknown
reviewersbz
bugs825392
milestone31.0a1
Bug 825392 - Infer the global from the reflector in DoInitJSClass. r=bz
dom/xbl/nsXBLBinding.cpp
dom/xbl/nsXBLBinding.h
dom/xbl/nsXBLProtoImpl.cpp
dom/xbl/nsXBLPrototypeBinding.cpp
dom/xbl/nsXBLPrototypeBinding.h
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -914,27 +914,34 @@ nsXBLBinding::WalkRules(nsIStyleRuleProc
   if (rules)
     (*aFunc)(rules, aData);
 }
 
 // Internal helper methods ////////////////////////////////////////////////////////////////
 
 // static
 nsresult
-nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
+nsXBLBinding::DoInitJSClass(JSContext *cx,
                             JS::Handle<JSObject*> obj,
                             const nsAFlatCString& aClassName,
                             nsXBLPrototypeBinding* aProtoBinding,
                             JS::MutableHandle<JSObject*> aClassObject,
                             bool* aNew)
 {
   // First ensure our JS class is initialized.
   nsAutoCString className(aClassName);
   nsAutoCString xblKey(aClassName);
 
+  // Note that, now that NAC reflectors are created in the XBL scope, the
+  // reflector is not necessarily same-compartment with the document. So we'll
+  // end up creating a separate instance of the oddly-named XBL class object
+  // and defining it as a property on the XBL scope's global. This works fine,
+  // but we need to make sure never to assume that the the reflector and
+  // prototype are same-compartment with the bound document.
+  JS::RootedObject global(cx, js::GetGlobalForObjectCrossCompartment(obj));
   JSAutoCompartment ac(cx, global);
 
   JS::Rooted<JSObject*> parent_proto(cx, nullptr);
   nsXBLJSClass* c = nullptr;
   if (obj) {
     // Retrieve the current prototype of obj.
     if (!JS_GetPrototype(cx, obj, &parent_proto)) {
       return NS_ERROR_FAILURE;
--- a/dom/xbl/nsXBLBinding.h
+++ b/dom/xbl/nsXBLBinding.h
@@ -129,18 +129,17 @@ public:
 
   void AttributeChanged(nsIAtom* aAttribute, int32_t aNameSpaceID,
                         bool aRemoveFlag, bool aNotify);
 
   void ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument);
 
   void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
 
-  static nsresult DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
-                                JS::Handle<JSObject*> obj,
+  static nsresult DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> obj,
                                 const nsAFlatCString& aClassName,
                                 nsXBLPrototypeBinding* aProtoBinding,
                                 JS::MutableHandle<JSObject*> aClassObject,
                                 bool* aNew);
 
   bool AllowScripts();
 
   mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild);
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -183,17 +183,17 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLP
   NS_ENSURE_SUCCESS(rv, rv);
 
   JS::Rooted<JSObject*> value(cx, &v.toObject());
 
   // All of the above code was just obtaining the bound element's script object and its immediate
   // concrete base class.  We need to alter the object so that our concrete class is interposed
   // between the object and its base class.  We become the new base class of the object, and the
   // object's old base class becomes the new class' base class.
-  rv = aBinding->InitClass(mClassName, cx, global, value, aTargetClassObject, aTargetIsNew);
+  rv = aBinding->InitClass(mClassName, cx, value, aTargetClassObject, aTargetIsNew);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   aBoundElement->PreserveWrapper(aBoundElement);
 
   return rv;
 }
@@ -206,17 +206,17 @@ nsXBLProtoImpl::CompilePrototypeMembers(
   // context.
   AutoSafeJSContext cx;
   JS::Rooted<JSObject*> compilationGlobal(cx, aBinding->XBLDocumentInfo()->GetCompilationGlobal());
   NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
   JSAutoCompartment ac(cx, compilationGlobal);
 
   JS::Rooted<JSObject*> classObject(cx);
   bool classObjectIsNew = false;
-  nsresult rv = aBinding->InitClass(mClassName, cx, compilationGlobal, compilationGlobal,
+  nsresult rv = aBinding->InitClass(mClassName, cx, compilationGlobal,
                                     &classObject, &classObjectIsNew);
   if (NS_FAILED(rv))
     return rv;
 
   MOZ_ASSERT(classObjectIsNew);
   MOZ_ASSERT(classObject);
   mClassObject = classObject;
 
@@ -336,17 +336,17 @@ nsXBLProtoImpl::Read(nsIObjectInputStrea
 {
   AssertInCompilationScope();
   AutoJSContext cx;
   // Set up a class object first so that deserialization is possible
   JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
 
   JS::Rooted<JSObject*> classObject(cx);
   bool classObjectIsNew = false;
-  nsresult rv = aBinding->InitClass(mClassName, cx, global, global, &classObject,
+  nsresult rv = aBinding->InitClass(mClassName, cx, global, &classObject,
                                     &classObjectIsNew);
   NS_ENSURE_SUCCESS(rv, rv);
   MOZ_ASSERT(classObject);
   MOZ_ASSERT(classObjectIsNew);
 
   mClassObject = classObject;
 
   nsXBLProtoImplField* previousField = nullptr;
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -442,22 +442,21 @@ nsXBLPrototypeBinding::GetImmediateChild
   }
 
   return nullptr;
 }
 
 nsresult
 nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
                                  JSContext * aContext,
-                                 JS::Handle<JSObject*> aGlobal,
                                  JS::Handle<JSObject*> aScriptObject,
                                  JS::MutableHandle<JSObject*> aClassObject,
                                  bool* aNew)
 {
-  return nsXBLBinding::DoInitJSClass(aContext, aGlobal, aScriptObject,
+  return nsXBLBinding::DoInitJSClass(aContext, aScriptObject,
                                      aClassName, this, aClassObject, aNew);
 }
 
 nsIContent*
 nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
                                       nsIContent* aTemplRoot,
                                       nsIContent* aCopyRoot, 
                                       nsIContent* aTemplChild)
--- a/dom/xbl/nsXBLPrototypeBinding.h
+++ b/dom/xbl/nsXBLPrototypeBinding.h
@@ -85,17 +85,16 @@ public:
     }
   }
 
   const nsCString& ClassName() const {
     return mImplementation ? mImplementation->mClassName : EmptyCString();
   }
 
   nsresult InitClass(const nsCString& aClassName, JSContext * aContext,
-                     JS::Handle<JSObject*> aGlobal,
                      JS::Handle<JSObject*> aScriptObject,
                      JS::MutableHandle<JSObject*> aClassObject,
                      bool* aNew);
 
   nsresult ConstructInterfaceTable(const nsAString& aImpls);
 
   void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; }
   nsXBLProtoImpl* GetImplementation() { return mImplementation; }