fix bug 94752. Let xpconnect decide when to call JS_DestroyContext. It sometimes needs to defer the call until JS code running on the context is finished. r=dbradley sr=jst

git-svn-id: svn://10.0.0.236/trunk@101079 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jband%netscape.com 2001-08-15 04:49:09 +00:00
parent e966de8073
commit 9a7d33e56a
8 changed files with 106 additions and 9 deletions

View File

@ -228,7 +228,8 @@ nsJSContext::DOMBranchCallback(JSContext *cx, JSScript *script)
{
// Get the native context
nsJSContext *ctx = NS_STATIC_CAST(nsJSContext *, ::JS_GetContextPrivate(cx));
NS_ENSURE_TRUE(ctx, JS_TRUE);
if (!ctx)
return JS_TRUE;
// Filter out most of the calls to this callback
if (++ctx->mBranchCallbackCount & MAYBE_GC_BRANCH_COUNT_MASK)
@ -383,15 +384,12 @@ nsJSContext::~nsJSContext()
this);
}
/* Remove global object reference to window object, so it can be collected. */
::JS_SetGlobalObject(mContext, nsnull); // XXX: Do we need this call?
::JS_DestroyContext(mContext);
// Let xpconnect resync its JSContext tracker.
// Let xpconnect destroy the JSContext when it thinks the time is right.
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
if (xpc) {
xpc->SyncJSContexts();
xpc->ReleaseJSContext(mContext, PR_FALSE);
} else {
::JS_DestroyContext(mContext);
}
}

View File

@ -569,6 +569,8 @@ interface nsIXPConnect : nsISupports
attribute PRBool collectGarbageOnMainThreadOnly;
attribute PRBool deferReleasesUntilAfterGarbageCollection;
void releaseJSContext(in JSContextPtr aJSContext, in PRBool noGC);
};

View File

@ -969,6 +969,51 @@ nsXPConnect::SetDeferReleasesUntilAfterGarbageCollection(PRBool aDeferReleasesUn
return NS_OK;
}
/* void releaseJSContext (in JSContextPtr aJSContext, in PRBool noGC); */
NS_IMETHODIMP
nsXPConnect::ReleaseJSContext(JSContext * aJSContext, PRBool noGC)
{
NS_ASSERTION(aJSContext, "bad param");
XPCPerThreadData* tls = XPCPerThreadData::GetData();
if(tls)
{
XPCCallContext* ccx = nsnull;
for(XPCCallContext* cur = tls->GetCallContext();
cur;
cur = cur->GetPrevCallContext())
{
if(cur->GetJSContext() == aJSContext)
{
ccx = cur;
// Keep looping to find the deepest matching call context.
}
}
if(ccx)
{
#ifdef DEBUG_xpc_hacker
printf("!xpc - deferring destruction of JSContext @ %0x\n",
aJSContext);
#endif
ccx->SetDestroyJSContextInDestructor(JS_TRUE);
return NS_OK;
}
// else continue on and synchronously destroy the JSContext ...
NS_ASSERTION(!tls->GetJSContextStack() ||
!tls->GetJSContextStack()->
DEBUG_StackHasJSContext(aJSContext),
"JSContext still in threadjscontextstack!");
}
if(noGC)
JS_DestroyContextNoGC(aJSContext);
else
JS_DestroyContext(aJSContext);
SyncJSContexts();
return NS_OK;
}
/* void debugDump (in short depth); */
NS_IMETHODIMP
nsXPConnect::DebugDump(PRInt16 depth)

View File

@ -51,6 +51,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
mXPCContext(nsnull),
mJSContext(cx),
mContextPopRequired(JS_FALSE),
mDestroyJSContextInDestructor(JS_FALSE),
mCallerLanguage(callerLanguage)
{
NS_INIT_ISUPPORTS();
@ -312,8 +313,25 @@ XPCCallContext::~XPCCallContext()
}
if(mJSContext)
{
if(mCallerLanguage == NATIVE_CALLER && JS_GetContextThread(mJSContext))
JS_EndRequest(mJSContext);
if(mDestroyJSContextInDestructor)
{
#ifdef DEBUG_xpc_hacker
printf("!xpc - doing deferred destruction of JSContext @ %0x\n",
mJSContext);
#endif
NS_ASSERTION(!mThreadData->GetJSContextStack() ||
!mThreadData->GetJSContextStack()->
DEBUG_StackHasJSContext(mJSContext),
"JSContext still in threadjscontextstack!");
JS_DestroyContext(mJSContext);
mXPC->SyncJSContexts();
}
}
NS_IF_RELEASE(mXPC);
}

View File

@ -315,6 +315,20 @@ XPCCallContext::SetMethodIndex(PRUint16 index)
mMethodIndex = index;
}
inline JSBool
XPCCallContext::GetDestroyJSContextInDestructor() const
{
CHECK_STATE(HAVE_CONTEXT);
return mDestroyJSContextInDestructor;
}
inline void
XPCCallContext::SetDestroyJSContextInDestructor(JSBool b)
{
CHECK_STATE(HAVE_CONTEXT);
mDestroyJSContextInDestructor = b;
}
/***************************************************************************/
inline const nsIID*

View File

@ -763,6 +763,9 @@ public:
inline PRUint16 GetMethodIndex() const ;
inline void SetMethodIndex(PRUint16 index) ;
inline JSBool GetDestroyJSContextInDestructor() const;
inline void SetDestroyJSContextInDestructor(JSBool b);
inline jsval GetResolveName() const;
inline jsval SetResolveName(jsval name);
@ -816,6 +819,7 @@ private:
XPCContext* mXPCContext;
JSContext* mJSContext;
JSBool mContextPopRequired;
JSBool mDestroyJSContextInDestructor;
XPCContext::LangType mCallerLanguage;
@ -2464,6 +2468,10 @@ public:
XPCJSContextStack();
virtual ~XPCJSContextStack();
#ifdef DEBUG
JSBool DEBUG_StackHasJSContext(JSContext* aJSContext);
#endif
private:
void SyncJSContexts();

View File

@ -103,6 +103,17 @@ XPCJSContextStack::Push(JSContext * cx)
return NS_OK;
}
#ifdef DEBUG
JSBool
XPCJSContextStack::DEBUG_StackHasJSContext(JSContext* aJSContext)
{
for(PRInt32 i; i < mStack.GetSize(); i++)
if(aJSContext == (JSContext*)mStack.ObjectAt(i))
return JS_TRUE;
return JS_FALSE;
}
#endif
JS_STATIC_DLL_CALLBACK(JSBool)
SafeGlobalResolve(JSContext *cx, JSObject *obj, jsval id)
{

View File

@ -527,7 +527,8 @@ nsStreamXferOp::OnStopRequest( nsIRequest *request,
// Notify observer that the download is complete.
if ( !mError && mObserver ) {
rv = mObserver->Observe( (nsIStreamTransferOperation*)this,
nsCOMPtr<nsIObserver> kungFuDeathGrip(mObserver);
rv = kungFuDeathGrip->Observe( (nsIStreamTransferOperation*)this,
NS_ConvertASCIItoUCS2( NS_ISTREAMTRANSFER_CONTRACTID ";onCompletion" ).get(),
nsnull );
if ( NS_FAILED( rv ) ) {