Fix for bug 379593 (Only create one XPCCallContext per cycle collection). r=jst, sr=brendan.
authorpeterv@propagandism.org
Fri, 04 May 2007 01:55:08 -0700
changeset 1084 c843d213847b39e7a2ebf7fd2fa5cb16992fb0cd
parent 1083 116637ada9570e9e477aaf6710158c6621a414a3
child 1085 1243d0ab9771341951fbbbbf11a571c8cd835fb8
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst, brendan
bugs379593
milestone1.9a5pre
Fix for bug 379593 (Only create one XPCCallContext per cycle collection). r=jst, sr=brendan.
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcprivate.h
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -68,17 +68,18 @@ const char XPC_XPCONNECT_CONTRACTID[]   
 
 nsXPConnect::nsXPConnect()
     :   mRuntime(nsnull),
         mInterfaceInfoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)),
         mContextStack(nsnull),
         mDefaultSecurityManager(nsnull),
         mDefaultSecurityManagerFlags(0),
         mShuttingDown(JS_FALSE),
-        mObjRefcounts(nsnull)
+        mObjRefcounts(nsnull),
+        mCycleCollectionContext(nsnull)
 {
     // Ignore the result. If the runtime service is not ready to rumble
     // then we'll set this up later as needed.
     CreateRuntime();
 
     CallGetService(XPC_CONTEXT_STACK_CONTRACTID, &mContextStack);
 
     nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this);
@@ -216,16 +217,18 @@ struct JSObjectRefcounts
 
 nsXPConnect::~nsXPConnect()
 {
     // XXX It would be nice if we could get away with doing a GC here and also
     // calling Release on the natives no longer reachable via XPConnect. As
     // noted all over the place, this makes bad things happen since shutdown is
     // an unstable time for so many modules who have not planned well for it.
 
+    NS_ASSERTION(!mCycleCollectionContext,
+                 "Didn't call FinishCycleCollection?");
     nsCycleCollector_forgetRuntime(nsIProgrammingLanguage::JAVASCRIPT);
     if (mObjRefcounts)
     {
         delete mObjRefcounts;
         mObjRefcounts = NULL;
     }
 
     mShuttingDown = JS_TRUE;
@@ -546,87 +549,105 @@ void XPCMarkNotification(void *thing, ui
 
 nsresult 
 nsXPConnect::BeginCycleCollection()
 {
     if (!mObjRefcounts)
         mObjRefcounts = new JSObjectRefcounts;
 
     mObjRefcounts->MarkStart();
-    XPCCallContext cx(NATIVE_CALLER);
-    if (cx.IsValid()) {
-        gOldJSGCCallback = JS_SetGCCallback(cx, XPCCycleGCCallback);
-        JS_SetGCThingCallback(cx, XPCMarkNotification, mObjRefcounts);
-        JS_GC(cx);
-        JS_SetGCThingCallback(cx, nsnull, nsnull);
-        JS_SetGCCallback(cx, gOldJSGCCallback);
-        gOldJSGCCallback = nsnull;
+
+    NS_ASSERTION(!mCycleCollectionContext,
+                 "Didn't call FinishCycleCollection?");
+    mCycleCollectionContext = new XPCCallContext(NATIVE_CALLER);
+    if(!mCycleCollectionContext || !mCycleCollectionContext->IsValid())
+    {
+        delete mCycleCollectionContext;
+        mCycleCollectionContext = nsnull;
+        return NS_ERROR_FAILURE;
+    }
+
+    JSContext *cx = mCycleCollectionContext->GetJSContext();
+    gOldJSGCCallback = JS_SetGCCallback(cx, XPCCycleGCCallback);
+    JS_SetGCThingCallback(cx, XPCMarkNotification, mObjRefcounts);
+    JS_GC(cx);
+    JS_SetGCThingCallback(cx, nsnull, nsnull);
+    JS_SetGCCallback(cx, gOldJSGCCallback);
+    gOldJSGCCallback = nsnull;
 
 #ifndef XPCONNECT_STANDALONE
-        NS_ASSERTION(mObjRefcounts->mScopes.Count() == 0,
-                     "Didn't clear mScopes?");
-        XPCWrappedNativeScope::TraverseScopes(cx);
+    NS_ASSERTION(mObjRefcounts->mScopes.Count() == 0, "Didn't clear mScopes?");
+    XPCWrappedNativeScope::TraverseScopes(*mCycleCollectionContext);
 #endif
-    }
 
     return NS_OK;
 }
 
 #ifndef XPCONNECT_STANDALONE
 void
 nsXPConnect::RecordTraversal(void *p, nsISupports *s)
 {
     mObjRefcounts->mScopes.Put(p, s);
 }
 #endif
 
 nsresult 
 nsXPConnect::FinishCycleCollection()
 {
+    delete mCycleCollectionContext;
+    mCycleCollectionContext = nsnull;
     if (mObjRefcounts)
         mObjRefcounts->Finish();
     return NS_OK;
 }
 
 nsresult 
 nsXPConnect::Root(const nsDeque &nodes)
 {
-    XPCCallContext cx(NATIVE_CALLER);
+    if(!mCycleCollectionContext)
+        return NS_ERROR_FAILURE;
+
+    JSContext *cx = mCycleCollectionContext->GetJSContext();
     for (PRInt32 i = 0; i < nodes.GetSize(); ++i)
     {
         void *p = nodes.ObjectAt(i);
         if (!p)
             continue;
         JSObject *obj = NS_STATIC_CAST(JSObject*, p);
         if (!JS_LockGCThing(cx, obj))
             return NS_ERROR_FAILURE;
     }
     return NS_OK;
 }
 
 nsresult 
 nsXPConnect::Unlink(const nsDeque &nodes)
 {
-    XPCCallContext cx(NATIVE_CALLER);
-    
+    if(!mCycleCollectionContext)
+        return NS_ERROR_FAILURE;
+
+    JSContext *cx = mCycleCollectionContext->GetJSContext();
     for (PRInt32 i = 0; i < nodes.GetSize(); ++i)
     {
         void *p = nodes.ObjectAt(i);
         if (!p)
             continue;
         JSObject *obj = NS_STATIC_CAST(JSObject*, p);
         JS_ClearScope(cx, obj);
     }
     return NS_OK;
 }
 
 nsresult 
 nsXPConnect::Unroot(const nsDeque &nodes)
 {
-    XPCCallContext cx(NATIVE_CALLER);
+    if(!mCycleCollectionContext)
+        return NS_ERROR_FAILURE;
+
+    JSContext *cx = mCycleCollectionContext->GetJSContext();
     for (PRInt32 i = 0; i < nodes.GetSize(); ++i)
     {
         void *p = nodes.ObjectAt(i);
         if (!p)
             continue;
         JSObject *obj = NS_STATIC_CAST(JSObject*, p);
         if (!JS_UnlockGCThing(cx, obj))
             return NS_ERROR_FAILURE;
@@ -648,17 +669,20 @@ TraverseJSScript(JSScript* script, nsCyc
             cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
                                ATOM_TO_OBJECT(atom));
     }
 }
 
 nsresult 
 nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
 {
-    XPCCallContext cx(NATIVE_CALLER);
+    if(!mCycleCollectionContext)
+        return NS_ERROR_FAILURE;
+
+    JSContext *cx = mCycleCollectionContext->GetJSContext();
 
     PRUint32 refcount = mObjRefcounts->Get(p);
     NS_ASSERTION(refcount > 0, "JS object but unknown to the JS GC?");
 
     JSObject *obj = NS_STATIC_CAST(JSObject*, p);
     JSClass* clazz = OBJ_GET_CLASS(cx, obj);
 
 #ifdef DEBUG_CC
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -506,16 +506,17 @@ private:
 
     XPCJSRuntime*            mRuntime;
     nsCOMPtr<nsIInterfaceInfoSuperManager> mInterfaceInfoManager;
     nsIThreadJSContextStack* mContextStack;
     nsIXPCSecurityManager*   mDefaultSecurityManager;
     PRUint16                 mDefaultSecurityManagerFlags;
     JSBool                   mShuttingDown;
     JSObjectRefcounts*       mObjRefcounts;
+    XPCCallContext*          mCycleCollectionContext;
 
 #ifdef XPC_TOOLS_SUPPORT
     nsCOMPtr<nsIXPCToolsProfiler> mProfiler;
     nsCOMPtr<nsILocalFile>        mProfilerOutputFile;
 #endif
 
 };