Bug 797304 - Replace MoveWrapper nonsense with orphan fixup. r=peterv
authorBobby Holley <bobbyholley@gmail.com>
Tue, 16 Oct 2012 15:07:54 +0200
changeset 110539 c37ac98907d13736321c28677917c85adc7e546a
parent 110538 a812a1ef0bfcc6221e07576ba95e7f96176343ec
child 110540 226cb9228a9e005da8769f28e655b3e05df44aac
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerspeterv
bugs797304
milestone19.0a1
Bug 797304 - Replace MoveWrapper nonsense with orphan fixup. r=peterv
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/html/document/src/nsHTMLDocument.cpp
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/src/nsXPConnect.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -195,24 +195,16 @@ class nsContentUtils
 public:
   static nsresult Init();
 
   /**
    * Get a JSContext from the document's scope object.
    */
   static JSContext* GetContextFromDocument(nsIDocument *aDocument);
 
-  /**
-   * When a document's scope changes (e.g., from document.open(), call this
-   * function to move all content wrappers from the old scope to the new one.
-   */
-  static nsresult ReparentContentWrappersInScope(JSContext *cx,
-                                                 nsIScriptGlobalObject *aOldScope,
-                                                 nsIScriptGlobalObject *aNewScope);
-
   static bool     IsCallerChrome();
 
   static bool     IsCallerTrustedForRead();
 
   static bool     IsCallerTrustedForWrite();
 
   /**
    * Check whether a caller has UniversalXPConnect.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1716,33 +1716,16 @@ nsContentUtils::TraceSafeJSContext(JSTra
   if (!cx) {
     return;
   }
   if (JSObject* global = JS_GetGlobalObject(cx)) {
     JS_CALL_OBJECT_TRACER(aTrc, global, "safe context");
   }
 }
 
-nsresult
-nsContentUtils::ReparentContentWrappersInScope(JSContext *cx,
-                                               nsIScriptGlobalObject *aOldScope,
-                                               nsIScriptGlobalObject *aNewScope)
-{
-  JSObject *oldScopeObj = aOldScope->GetGlobalJSObject();
-  JSObject *newScopeObj = aNewScope->GetGlobalJSObject();
-
-  if (!newScopeObj || !oldScopeObj) {
-    // We can't really do anything without the JSObjects.
-
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  return sXPConnect->MoveWrappers(cx, oldScopeObj, newScopeObj);
-}
-
 nsPIDOMWindow *
 nsContentUtils::GetWindowFromCaller()
 {
   JSContext *cx = nullptr;
   sThreadJSContextStack->Peek(&cx);
 
   if (cx) {
     nsCOMPtr<nsPIDOMWindow> win =
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1494,17 +1494,17 @@ nsHTMLDocument::Open(const nsAString& aC
     if (oldScope && newScope != oldScope) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
       nsCOMPtr<nsIXPConnectJSObjectHolder> ignored;
       rv = xpc->ReparentWrappedNativeIfFound(cx, oldScope->GetGlobalJSObject(),
                                              newScope->GetGlobalJSObject(),
                                              static_cast<nsINode*>(this),
                                              getter_AddRefs(ignored));
       NS_ENSURE_SUCCESS(rv, rv);
-      rv = nsContentUtils::ReparentContentWrappersInScope(cx, oldScope, newScope);
+      rv = xpc->RescueOrphansInScope(cx, oldScope->GetGlobalJSObject());
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   // Call Reset(), this will now do the full reset
   Reset(channel, group);
   if (baseURI) {
     mDocumentBaseURI = baseURI;
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -283,17 +283,17 @@ interface nsIXPCFunctionThisTranslator :
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[uuid(d94c13ae-7585-4e7b-b7ad-482976bc6f1b)]
+[uuid(e28a33ce-dfe9-4816-ae20-0f1dc8077230)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
      * Initializes classes on a global object that has already been created.
@@ -519,19 +519,17 @@ interface nsIXPConnect : nsISupports
                               in nsIXPCFunctionThisTranslator aTranslator);
 
     nsIXPConnectJSObjectHolder
     reparentWrappedNativeIfFound(in JSContextPtr aJSContext,
                                  in JSObjectPtr  aScope,
                                  in JSObjectPtr  aNewParent,
                                  in nsISupports  aCOMObj);
     void
-    moveWrappers(in JSContextPtr aJSContext,
-                 in JSObjectPtr  aOldScope,
-                 in JSObjectPtr  aNewScope);
+    rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr  aScope);
 
     void clearAllWrappedNativeSecurityPolicies();
 
     nsIXPConnectJSObjectHolder
     getWrappedNativePrototype(in JSContextPtr aJSContext,
                               in JSObjectPtr  aScope,
                               in nsIClassInfo aClassInfo);
 
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1546,160 +1546,43 @@ 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;
-    }
-
-    // For performance reasons, we wait to fix up orphaned wrappers (wrappers
-    // whose parents have moved to another scope) until right before they
-    // threaten to confuse us.
-    //
-    // If this wrapper is an orphan, reunite it with its parent. If, following
-    // that, the wrapper is no longer in the old scope, then we don't need to
-    // reparent it.
-    MOZ_ASSERT(wrapper->GetScope() == oldScope);
-    nsresult rv = wrapper->RescueOrphans(ccx);
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (wrapper->GetScope() != oldScope)
-        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 = nullptr;
-
-    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();
-    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;
-    }
-
-    // These are pretty special circumstances. Make sure that the parent here
-    // is a bonafide WN with a proper parent chain.
-    MOZ_ASSERT(!js::IsCrossCompartmentWrapper(newParent));
-    MOZ_ASSERT(IS_WRAPPER_CLASS(js::GetObjectClass(newParent)));
-    if (!IS_WN_WRAPPER_OBJECT(newParent))
-        NS_ENSURE_STATE(MorphSlimWrapper(ccx, newParent));
-    XPCWrappedNative *parentWrapper =
-      static_cast<XPCWrappedNative*>(js::GetObjectPrivate(newParent));
-    rv = parentWrapper->RescueOrphans(ccx);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // 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 = parentWrapper->GetScope();
-    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.
-
-        rv = MoveWrapper(ccx, parentWrapper, newScope, oldScope);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        // If the parent wanted to stay in the old scope, we have to stay with
-        // it. This can happen when doing document.write when the old detached
-        // about:blank document is still floating around in the scope. Leave it
-        // behind to die.
-        if (parentWrapper->GetScope() == oldScope)
-            return NS_OK;
-        NS_ASSERTION(parentWrapper->GetScope() == newScope,
-                     "A _third_ scope? Oh dear...");
-
-    } 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, parentWrapper->GetFlatJSObject(),
-                                                  wrapper->GetIdentityObject(),
-                                                  getter_AddRefs(junk));
-    return rv;
-}
-
-/* void moveWrappers(in JSContextPtr aJSContext, in JSObjectPtr  aOldScope, in JSObjectPtr  aNewScope); */
+/* void rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr  aScope); */
 NS_IMETHODIMP
-nsXPConnect::MoveWrappers(JSContext *aJSContext,
-                          JSObject *aOldScope,
-                          JSObject *aNewScope)
+nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScope)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    XPCWrappedNativeScope *oldScope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aOldScope);
-    if (!oldScope)
+    XPCWrappedNativeScope *scope =
+        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
+    if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    XPCWrappedNativeScope *newScope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aNewScope);
-    if (!newScope)
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-
-    // First, look through the old scope and find all of the wrappers that
-    // we're going to move.
+    // First, look through the old scope and find all of the wrappers that we
+    // might need to rescue.
     nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
 
     {   // scoped lock
         XPCAutoLock lock(GetRuntime()->GetMapLock());
-        Native2WrappedNativeMap *map = oldScope->GetWrappedNativeMap();
+        Native2WrappedNativeMap *map = scope->GetWrappedNativeMap();
         wrappersToMove.SetCapacity(map->Count());
         map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
     }
 
     // Now that we have the wrappers, reparent them to the new scope.
     for (uint32_t i = 0, stop = wrappersToMove.Length(); i < stop; ++i) {
-        nsresult rv = MoveWrapper(ccx, wrappersToMove[i], newScope, oldScope);
+        nsresult rv = wrappersToMove[i]->RescueOrphans(ccx);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
 }
 
 /* void setSecurityManagerForJSContext (in JSContextPtr aJSContext, in nsIXPCSecurityManager aManager, in uint16_t flags); */
 NS_IMETHODIMP