Bug 950909 - Forward native aggregation to the root XPCWrappedJS. r=mccr8, sr=smaug, a=bajaj
authorBobby Holley <bobbyholley@gmail.com>
Thu, 19 Dec 2013 18:08:07 -0800
changeset 175513 84b87ea8c0cc51a8d4850443e15793ad5ff8e086
parent 175512 342e386bc033b99d492aa6f970561a0ba990fe25
child 175514 9bb7691ca2c0e50c762406b7d1d4626e398fb6ae
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, smaug, bajaj
bugs950909
milestone28.0a2
Bug 950909 - Forward native aggregation to the root XPCWrappedJS. r=mccr8, sr=smaug, a=bajaj
dom/bindings/CallbackObject.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSWeakReference.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCWrappedJS.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/xpcprivate.h
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -221,18 +221,17 @@ CallbackObjectHolderBase::ToXPCOMCallbac
 
   AutoSafeJSContext cx;
 
   JS::Rooted<JSObject*> callback(cx, aCallback->Callback());
 
   JSAutoCompartment ac(cx, callback);
   nsRefPtr<nsXPCWrappedJS> wrappedJS;
   nsresult rv =
-    nsXPCWrappedJS::GetNewOrUsed(callback, aIID,
-                                 nullptr, getter_AddRefs(wrappedJS));
+    nsXPCWrappedJS::GetNewOrUsed(callback, aIID, getter_AddRefs(wrappedJS));
   if (NS_FAILED(rv) || !wrappedJS) {
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> retval;
   rv = wrappedJS->QueryInterface(aIID, getter_AddRefs(retval));
   if (NS_FAILED(rv)) {
     return nullptr;
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1023,20 +1023,26 @@ XPCConvert::JSObject2NativeInterface(voi
 
             return false;
         }
     }
 
     // else...
 
     nsXPCWrappedJS* wrapper;
-    nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, *iid, aOuter, &wrapper);
+    nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, *iid, &wrapper);
     if (pErr)
         *pErr = rv;
     if (NS_SUCCEEDED(rv) && wrapper) {
+        // If the caller wanted to aggregate this JS object to a native,
+        // attach it to the wrapper. Note that we allow a maximum of one
+        // aggregated native for a given XPCWrappedJS.
+        if (aOuter)
+            wrapper->SetAggregatedNativeObject(aOuter);
+
         // We need to go through the QueryInterface logic to make this return
         // the right thing for the various 'special' interfaces; e.g.
         // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
         // there is an outer to avoid nasty recursion.
         rv = aOuter ? wrapper->AggregatedQueryInterface(*iid, dest) :
                       wrapper->QueryInterface(*iid, dest);
         if (pErr)
             *pErr = rv;
@@ -1179,18 +1185,17 @@ XPCConvert::JSValToXPCException(MutableH
 
             if (found && !JS_HasProperty(cx, obj, "result", &found))
                 return NS_ERROR_FAILURE;
 
             if (found) {
                 // lets try to build a wrapper around the JSObject
                 nsXPCWrappedJS* jswrapper;
                 nsresult rv =
-                    nsXPCWrappedJS::GetNewOrUsed(obj, NS_GET_IID(nsIException),
-                                                 nullptr, &jswrapper);
+                    nsXPCWrappedJS::GetNewOrUsed(obj, NS_GET_IID(nsIException), &jswrapper);
                 if (NS_FAILED(rv))
                     return rv;
 
                 *exceptn = static_cast<nsIException *>(jswrapper->GetXPTCStub());
                 return NS_OK;
             }
 
 
--- a/js/xpconnect/src/XPCJSWeakReference.cpp
+++ b/js/xpconnect/src/XPCJSWeakReference.cpp
@@ -38,17 +38,16 @@ nsresult xpcJSWeakReference::Init(JSCont
     }
     // If it's not a wrapped native, or it is a wrapped native that does not
     // support weak references, fall back to getting a weak ref to the object.
 
     // See if object is a wrapped JSObject.
     nsRefPtr<nsXPCWrappedJS> wrapped;
     nsresult rv = nsXPCWrappedJS::GetNewOrUsed(obj,
                                                NS_GET_IID(nsISupports),
-                                               nullptr,
                                                getter_AddRefs(wrapped));
     if (!wrapped) {
         NS_ERROR("can't get nsISupportsWeakReference wrapper for obj");
         return rv;
     }
 
     return wrapped->GetWeakReference(getter_AddRefs(mReferent));
 }
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -723,18 +723,17 @@ xpc_qsUnwrapArgImpl(JSContext *cx,
     // Create the ccx needed for quick stubs.
     XPCCallContext ccx(JS_CALLER, cx);
     if (!ccx.IsValid()) {
         *ppArgRef = nullptr;
         return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
 
     nsRefPtr<nsXPCWrappedJS> wrappedJS;
-    rv = nsXPCWrappedJS::GetNewOrUsed(src, iid, nullptr,
-                                      getter_AddRefs(wrappedJS));
+    rv = nsXPCWrappedJS::GetNewOrUsed(src, iid, getter_AddRefs(wrappedJS));
     if (NS_FAILED(rv) || !wrappedJS) {
         *ppArgRef = nullptr;
         return rv;
     }
 
     // We need to go through the QueryInterface logic to make this return
     // the right thing for the various 'special' interfaces; e.g.
     // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -233,17 +233,16 @@ nsXPCWrappedJS::GetJSObject()
     }
     return mJSObj;
 }
 
 // static
 nsresult
 nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj,
                              REFNSIID aIID,
-                             nsISupports* aOuter,
                              nsXPCWrappedJS** wrapperResult)
 {
     // Do a release-mode assert against accessing nsXPCWrappedJS off-main-thread.
     if (!MOZ_LIKELY(NS_IsMainThread()))
         MOZ_CRASH();
 
     AutoJSContext cx;
     JSObject2WrappedJSMap* map;
@@ -277,50 +276,49 @@ nsXPCWrappedJS::GetNewOrUsed(JS::HandleO
             goto return_wrapper;
         }
     }
 
     if (!root) {
         // build the root wrapper
         if (rootJSObj == jsObj) {
             // the root will do double duty as the interface wrapper
-            wrapper = root = new nsXPCWrappedJS(cx, jsObj, clazz, nullptr,
-                                                aOuter);
+            wrapper = root = new nsXPCWrappedJS(cx, jsObj, clazz, nullptr);
             if (!root)
                 goto return_wrapper;
 
             map->Add(cx, root);
 
             goto return_wrapper;
         } else {
             // just a root wrapper
             nsXPCWrappedJSClass* rootClazz = nullptr;
             nsXPCWrappedJSClass::GetNewOrUsed(cx, NS_GET_IID(nsISupports),
                                               &rootClazz);
             if (!rootClazz)
                 goto return_wrapper;
 
-            root = new nsXPCWrappedJS(cx, rootJSObj, rootClazz, nullptr, aOuter);
+            root = new nsXPCWrappedJS(cx, rootJSObj, rootClazz, nullptr);
             NS_RELEASE(rootClazz);
 
             if (!root)
                 goto return_wrapper;
 
             release_root = true;
 
             map->Add(cx, root);
         }
     }
 
     // at this point we have a root and may need to build the specific wrapper
     MOZ_ASSERT(root,"bad root");
     MOZ_ASSERT(clazz,"bad clazz");
 
     if (!wrapper) {
-        wrapper = new nsXPCWrappedJS(cx, jsObj, clazz, root, aOuter);
+        wrapper = new nsXPCWrappedJS(cx, jsObj, clazz, root);
         if (!wrapper)
             goto return_wrapper;
     }
 
     wrapper->mNext = root->mNext;
     root->mNext = wrapper;
 
 return_wrapper:
@@ -335,31 +333,29 @@ return_wrapper:
 
     *wrapperResult = wrapper;
     return NS_OK;
 }
 
 nsXPCWrappedJS::nsXPCWrappedJS(JSContext* cx,
                                JSObject* aJSObj,
                                nsXPCWrappedJSClass* aClass,
-                               nsXPCWrappedJS* root,
-                               nsISupports* aOuter)
+                               nsXPCWrappedJS* root)
     : mJSObj(aJSObj),
       mClass(aClass),
       mRoot(root ? root : this),
       mNext(nullptr),
-      mOuter(root ? nullptr : aOuter)
+      mOuter(nullptr)
 {
     InitStub(GetClass()->GetIID());
 
     // intentionally do double addref - see Release().
     NS_ADDREF_THIS();
     NS_ADDREF_THIS();
     NS_ADDREF(aClass);
-    NS_IF_ADDREF(mOuter);
 
     if (mRoot != this)
         NS_ADDREF(mRoot);
 
 }
 
 nsXPCWrappedJS::~nsXPCWrappedJS()
 {
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -695,18 +695,17 @@ nsXPCWrappedJSClass::DelegatedQueryInter
         // we're looking for or we'll potentially bypass security
         // checks etc by calling directly through to a native found on
         // the prototype chain.
         //
         // Instead, simply do the nsXPCWrappedJS part of
         // XPConvert::JSObject2NativeInterface() here to make sure we
         // get a new (or used) nsXPCWrappedJS.
         nsXPCWrappedJS* wrapper;
-        nsresult rv = nsXPCWrappedJS::GetNewOrUsed(jsobj, aIID, nullptr,
-                                                   &wrapper);
+        nsresult rv = nsXPCWrappedJS::GetNewOrUsed(jsobj, aIID, &wrapper);
         if (NS_SUCCEEDED(rv) && wrapper) {
             // We need to go through the QueryInterface logic to make
             // this return the right thing for the various 'special'
             // interfaces; e.g.  nsIPropertyBag.
             rv = wrapper->QueryInterface(aIID, aInstancePtr);
             NS_RELEASE(wrapper);
             return rv;
         }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2474,17 +2474,16 @@ public:
     * This is rarely called directly. Instead one usually calls
     * XPCConvert::JSObject2NativeInterface which will handles cases where the
     * JS object is already a wrapped native or a DOM object.
     */
 
     static nsresult
     GetNewOrUsed(JS::HandleObject aJSObj,
                  REFNSIID aIID,
-                 nsISupports* aOuter,
                  nsXPCWrappedJS** wrapper);
 
     nsISomeInterface* GetXPTCStub() { return mXPTCStub; }
 
     /**
      * This getter does not change the color of the JSObject meaning that the
      * object returned is not guaranteed to be kept alive past the next CC.
      *
@@ -2511,28 +2510,36 @@ public:
     // last (outside) reference was released. Wrappers that fit into that
     // category are only deleted when we see that their corresponding JSObject
     // is to be finalized.
     bool IsSubjectToFinalization() const {return IsValid() && mRefCnt == 1;}
     bool IsObjectAboutToBeFinalized() {return JS_IsAboutToBeFinalized(&mJSObj);}
 
     bool IsAggregatedToNative() const {return mRoot->mOuter != nullptr;}
     nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}
+    void SetAggregatedNativeObject(nsISupports *aNative) {
+        MOZ_ASSERT(aNative);
+        if (mRoot->mOuter) {
+            MOZ_ASSERT(mRoot->mOuter == aNative,
+                       "Only one aggregated native can be set");
+            return;
+        }
+        NS_ADDREF(mRoot->mOuter = aNative);
+    }
 
     void TraceJS(JSTracer* trc);
     static void GetTraceName(JSTracer* trc, char *buf, size_t bufsize);
 
     virtual ~nsXPCWrappedJS();
 protected:
     nsXPCWrappedJS();   // not implemented
     nsXPCWrappedJS(JSContext* cx,
                    JSObject* aJSObj,
                    nsXPCWrappedJSClass* aClass,
-                   nsXPCWrappedJS* root,
-                   nsISupports* aOuter);
+                   nsXPCWrappedJS* root);
 
    void Unlink();
 
 private:
     JS::Heap<JSObject*> mJSObj;
     nsXPCWrappedJSClass* mClass;
     nsXPCWrappedJS* mRoot;
     nsXPCWrappedJS* mNext;