Bug 623810. First part, fix moving wrappers from one scope to another. r=mrbkap@gmail.com, a=blocker
authorJohnny Stenback <jst@mozilla.com>
Fri, 21 Jan 2011 16:59:18 -0800
changeset 61142 fb8e4cdf2346a4752a47aadaeb2866d0255df19d
parent 61141 eab0007fa9d4c287091e9bde94084366e0ae3825
child 61143 e3b9490af708327b4ec0c3853b409ccacd0d4c44
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersmrbkap, blocker
bugs623810
milestone2.0b10pre
Bug 623810. First part, fix moving wrappers from one scope to another. r=mrbkap@gmail.com, a=blocker
dom/base/nsGlobalWindow.cpp
js/src/xpconnect/src/nsXPConnect.cpp
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2070,19 +2070,19 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       {
         JSAutoEnterCompartment ac;
         if (!ac.enter(cx, mJSObject)) {
           NS_ERROR("unable to enter a compartment");
           return NS_ERROR_FAILURE;
         }
 
         JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
+
+        mContext->SetOuterObject(mJSObject);
       }
-
-      mContext->SetOuterObject(mJSObject);
     }
 
     JSAutoEnterCompartment ac;
     if (!ac.enter(cx, mJSObject)) {
       NS_ERROR("unable to enter a compartment");
       return NS_ERROR_FAILURE;
     }
 
@@ -2105,16 +2105,22 @@ nsGlobalWindow::SetNewDocument(nsIDocume
                              JS_PropertyStub, JS_PropertyStub,
                              JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
         NS_ERROR("can't create the 'window' property");
         return NS_ERROR_FAILURE;
       }
     }
   }
 
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(cx, mJSObject)) {
+    NS_ERROR("unable to enter a compartment");
+    return NS_ERROR_FAILURE;
+  }
+
   if (!aState && !reUseInnerWindow) {
     // Loading a new page and creating a new inner window, *not*
     // restoring from session history.
 
     // Now that both the the inner and outer windows are initialized
     // let the script context do its magic to hook them together.
     mContext->ConnectToInner(newInnerWindow, mJSObject);
 
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1504,16 +1504,111 @@ MoveableWrapperFinder(JSDHashTable *tabl
 
     // If a wrapper is expired, then there are no references to it from JS, so
     // we don't have to move it.
     if(!wn->IsWrapperExpired())
         array->AppendElement(wn);
     return JS_DHASH_NEXT;
 }
 
+static nsresult
+MoveWrapper(XPCCallContext& ccx, XPCWrappedNative *wrapper,
+            XPCWrappedNativeScope *newScope, XPCWrappedNativeScope *oldScope)
+{
+    // First, check to see if this wrapper really needs to be
+    // reparented.
+
+    if (wrapper->GetScope() == newScope)
+    {
+        // The wrapper already got moved, nothing to do here.
+        return NS_OK;
+    }
+
+    nsISupports *identity = wrapper->GetIdentityObject();
+    nsCOMPtr<nsIClassInfo> info(do_QueryInterface(identity));
+
+    // ClassInfo is implemented as singleton objects. If the identity
+    // object here is the same object as returned by the QI, then it
+    // is the singleton classinfo, so we don't need to reparent it.
+    if(SameCOMIdentity(identity, info))
+        info = nsnull;
+
+    if(!info)
+        return NS_OK;
+
+    XPCNativeScriptableCreateInfo sciProto;
+    XPCNativeScriptableCreateInfo sci;
+    const XPCNativeScriptableCreateInfo& sciWrapper =
+        XPCWrappedNative::GatherScriptableCreateInfo(identity, info,
+                                                     sciProto, sci);
+
+    // If the wrapper doesn't want precreate, then we don't need to
+    // worry about reparenting it.
+    if(!sciWrapper.GetFlags().WantPreCreate())
+        return NS_OK;
+
+    JSObject *newParent = oldScope->GetGlobalJSObject();
+    nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
+                                                      newParent,
+                                                      &newParent);
+    if(NS_FAILED(rv))
+        return rv;
+
+    if(newParent == oldScope->GetGlobalJSObject())
+    {
+        // The old scope still works for this wrapper. We have to
+        // assume that the wrapper will continue to return the old
+        // scope from PreCreate, so don't move it.
+        return NS_OK;
+    }
+
+    // The wrapper returned a new parent. If the new parent is in a
+    // different scope, then we need to reparent it, otherwise, the
+    // old scope is fine.
+
+    XPCWrappedNativeScope *betterScope =
+        XPCWrappedNativeScope::FindInJSObjectScope(ccx, newParent);
+    if(betterScope == oldScope)
+    {
+        // The wrapper asked for a different object, but that object
+        // was in the same scope. This means that the new parent
+        // simply hasn't been reparented yet, so reparent it first,
+        // and then continue reparenting the wrapper itself.
+
+        if (!IS_WN_WRAPPER_OBJECT(newParent)) {
+            // The parent of wrapper is a slim wrapper, in this case
+            // we need to morph the parent so that we can reparent it.
+
+            rv = MorphSlimWrapper(ccx, newParent);
+            NS_ENSURE_SUCCESS(rv, rv);
+        }
+
+        XPCWrappedNative *parentWrapper =
+            XPCWrappedNative::GetWrappedNativeOfJSObject(ccx, newParent);
+
+        rv = MoveWrapper(ccx, parentWrapper, newScope, oldScope);
+
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        newParent = parentWrapper->GetFlatJSObjectNoMark();
+    }
+    else
+        NS_ASSERTION(betterScope == newScope, "Weird scope returned");
+
+    // Now, reparent the wrapper, since we know that it wants to be
+    // reparented.
+
+    nsRefPtr<XPCWrappedNative> junk;
+    rv = XPCWrappedNative::ReparentWrapperIfFound(ccx, oldScope,
+                                                  newScope, newParent,
+                                                  wrapper->GetIdentityObject(),
+                                                  getter_AddRefs(junk));
+    return rv;
+}
+
 /* void moveWrappers(in JSContextPtr aJSContext, in JSObjectPtr  aOldScope, in JSObjectPtr  aNewScope); */
 NS_IMETHODIMP
 nsXPConnect::MoveWrappers(JSContext *aJSContext,
                           JSObject *aOldScope,
                           JSObject *aNewScope)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if(!ccx.IsValid())
@@ -1538,82 +1633,17 @@ nsXPConnect::MoveWrappers(JSContext *aJS
         Native2WrappedNativeMap *map = oldScope->GetWrappedNativeMap();
         wrappersToMove.SetCapacity(map->Count());
         map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
     }
 
     // Now that we have the wrappers, reparent them to the new scope.
     for(PRUint32 i = 0, stop = wrappersToMove.Length(); i < stop; ++i)
     {
-        // First, check to see if this wrapper really needs to be
-        // reparented.
-
-        XPCWrappedNative *wrapper = wrappersToMove[i];
-        nsISupports *identity = wrapper->GetIdentityObject();
-        nsCOMPtr<nsIClassInfo> info(do_QueryInterface(identity));
-
-        // ClassInfo is implemented as singleton objects. If the identity
-        // object here is the same object as returned by the QI, then it
-        // is the singleton classinfo, so we don't need to reparent it.
-        if(SameCOMIdentity(identity, info))
-            info = nsnull;
-
-        if(!info)
-            continue;
-
-        XPCNativeScriptableCreateInfo sciProto;
-        XPCNativeScriptableCreateInfo sci;
-        const XPCNativeScriptableCreateInfo& sciWrapper =
-            XPCWrappedNative::GatherScriptableCreateInfo(identity, info,
-                                                         sciProto, sci);
-
-        // If the wrapper doesn't want precreate, then we don't need to
-        // worry about reparenting it.
-        if(!sciWrapper.GetFlags().WantPreCreate())
-            continue;
-
-        JSObject *newParent = aOldScope;
-        nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
-                                                          aOldScope,
-                                                          &newParent);
-        if(NS_FAILED(rv))
-            return rv;
-
-        if(newParent == aOldScope)
-        {
-            // The old scope still works for this wrapper. We have to assume
-            // that the wrapper will continue to return the old scope from
-            // PreCreate, so don't move it.
-            continue;
-        }
-
-        // The wrapper returned a new parent. If the new parent is in
-        // a different scope, then we need to reparent it, otherwise,
-        // the old scope is fine.
-
-        XPCWrappedNativeScope *betterScope =
-            XPCWrappedNativeScope::FindInJSObjectScope(ccx, newParent);
-        if(betterScope == oldScope)
-        {
-            // The wrapper asked for a different object, but that object
-            // was in the same scope. We assume here that the new parent
-            // simply hasn't been reparented yet.
-            newParent = nsnull;
-        }
-        else
-            NS_ASSERTION(betterScope == newScope, "Weird scope returned");
-
-        // Now, reparent the wrapper, since we know that it wants to be
-        // reparented.
-
-        nsRefPtr<XPCWrappedNative> junk;
-        rv = XPCWrappedNative::ReparentWrapperIfFound(ccx, oldScope,
-                                                      newScope, newParent,
-                                                      wrapper->GetIdentityObject(),
-                                                      getter_AddRefs(junk));
+        nsresult rv = MoveWrapper(ccx, wrappersToMove[i], newScope, oldScope);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
 }
 
 /* void setSecurityManagerForJSContext (in JSContextPtr aJSContext, in nsIXPCSecurityManager aManager, in PRUint16 flags); */
 NS_IMETHODIMP