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:
parent
e966de8073
commit
9a7d33e56a
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -569,6 +569,8 @@ interface nsIXPConnect : nsISupports
|
||||
|
||||
attribute PRBool collectGarbageOnMainThreadOnly;
|
||||
attribute PRBool deferReleasesUntilAfterGarbageCollection;
|
||||
|
||||
void releaseJSContext(in JSContextPtr aJSContext, in PRBool noGC);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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*
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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 ) ) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user