Bug 520386. Don't clear scope while executing code in that scope. r=bzbarsky@mit.edu, sr=jst@mozilla.org

This commit is contained in:
Blake Kaplan
2009-11-19 15:11:44 -08:00
parent e553e503c6
commit a90ccae37f
5 changed files with 87 additions and 12 deletions

View File

@@ -930,6 +930,55 @@ nsGlobalWindow::ClearControllers()
}
}
class ClearScopeEvent : public nsRunnable
{
public:
ClearScopeEvent(nsGlobalWindow *innerWindow)
: mInnerWindow(innerWindow) {
}
NS_IMETHOD Run()
{
mInnerWindow->ReallyClearScope(this);
return NS_OK;
}
private:
nsRefPtr<nsGlobalWindow> mInnerWindow;
};
void
nsGlobalWindow::ReallyClearScope(nsRunnable *aRunnable)
{
NS_ASSERTION(IsInnerWindow(), "Must be an inner window");
nsIScriptContext *jsscx = GetContextInternal();
if (jsscx && jsscx->GetExecutingScript()) {
if (!aRunnable) {
aRunnable = new ClearScopeEvent(this);
if (!aRunnable) {
// The only reason that we clear scope here is to try to prevent
// leaks. Failing to clear scope might mean that we'll leak more
// but if we don't have enough memory to allocate a ClearScopeEvent
// we probably don't have to worry about this anyway.
return;
}
}
NS_DispatchToMainThread(aRunnable);
return;
}
PRUint32 lang_id;
NS_STID_FOR_ID(lang_id) {
// Note that scx comes from the outer window. If this is an inner
// window, it may not be the current inner for its outer.
nsIScriptContext *scx = GetScriptContextInternal(lang_id);
if (scx)
scx->ClearScope(mScriptGlobals[NS_STID_INDEX(lang_id)], PR_TRUE);
}
}
void
nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
{
@@ -983,14 +1032,9 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
}
if (aClearScope) {
PRUint32 lang_id;
NS_STID_FOR_ID(lang_id) {
// Note that scx comes from the outer window. If this is an inner
// window, it may not be the current inner for its outer.
nsIScriptContext *scx = GetScriptContextInternal(lang_id);
if (scx)
scx->ClearScope(mScriptGlobals[NS_STID_INDEX(lang_id)], PR_TRUE);
}
// NB: This might not clear our scope, but fire an event to do so
// instead.
ReallyClearScope(nsnull);
}
if (mDummyJavaPluginOwner) {

View File

@@ -122,6 +122,7 @@ class nsGlobalWindowObserver;
class nsGlobalWindow;
class nsDummyJavaPluginOwner;
class PostMessageEvent;
class nsRunnable;
class nsDOMOfflineResourceList;
class nsGeolocation;
@@ -238,6 +239,7 @@ public:
nsPIDOMWindow* GetPrivateParent();
// callback for close event
void ReallyCloseWindow();
void ReallyClearScope(nsRunnable *aRunnable);
// nsISupports
NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View File

@@ -56,10 +56,10 @@ class nsScriptObjectHolder;
typedef void (*nsScriptTerminationFunc)(nsISupports* aRef);
// 87482b5e-e019-4df5-9bc2-b2a51b1f2d28
// A4FE2B52-62B5-40C3-BF9C-5E0A27B10F90
#define NS_ISCRIPTCONTEXT_IID \
{ 0x87482b5e, 0xe019, 0x4df5, \
{ 0x9b, 0xc2, 0xb2, 0xa5, 0x1b, 0x1f, 0x2d, 0x28 } }
{ 0xA4FE2B52, 0x62B5, 0x40C3, \
{ 0xBF, 0x9C, 0x5E, 0x0A, 0x27, 0xB1, 0x0F, 0x90 } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */
@@ -402,6 +402,11 @@ public:
virtual PRBool GetProcessingScriptTag() = 0;
virtual void SetProcessingScriptTag(PRBool aResult) = 0;
/**
* Called to find out if this script context might be executing script.
*/
virtual PRBool GetExecutingScript() = 0;
/**
* Tell the context whether or not to GC when destroyed. An optimization
* used when the window is a [i]frame, so GC will happen anyway.

View File

@@ -1312,7 +1312,9 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
return 0;
}
nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
nsJSContext::nsJSContext(JSRuntime *aRuntime)
: mGCOnDestruction(PR_TRUE),
mExecuteDepth(0)
{
++sContextCount;
@@ -1522,6 +1524,8 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
JSAutoRequest ar(mContext);
nsJSVersionSetter setVersion(mContext, aVersion);
++mExecuteDepth;
ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
(JSObject *)aScopeObject,
jsprin,
@@ -1531,6 +1535,8 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
aLineNo,
&val);
--mExecuteDepth;
if (!ok) {
// Tell XPConnect about any pending exceptions. This is needed
// to avoid dropping JS exceptions in case we got here through
@@ -1688,6 +1694,8 @@ nsJSContext::EvaluateString(const nsAString& aScript,
nsJSContext::TerminationFuncHolder holder(this);
++mExecuteDepth;
// SecurityManager said "ok", but don't compile if aVersion is unknown.
// Since the caller is responsible for parsing the version strings, we just
// check it isn't JSVERSION_UNKNOWN.
@@ -1731,6 +1739,8 @@ nsJSContext::EvaluateString(const nsAString& aScript,
}
}
--mExecuteDepth;
// Pop here, after JS_ValueToString and any other possible evaluation.
if (NS_FAILED(stack->Pop(nsnull)))
rv = NS_ERROR_FAILURE;
@@ -1849,6 +1859,7 @@ nsJSContext::ExecuteScript(void *aScriptObject,
nsJSContext::TerminationFuncHolder holder(this);
JSAutoRequest ar(mContext);
++mExecuteDepth;
ok = ::JS_ExecuteScript(mContext,
(JSObject *)aScopeObject,
(JSScript*)::JS_GetPrivate(mContext,
@@ -1868,6 +1879,8 @@ nsJSContext::ExecuteScript(void *aScriptObject,
}
}
--mExecuteDepth;
// Pop here, after JS_ValueToString and any other possible evaluation.
if (NS_FAILED(stack->Pop(nsnull)))
rv = NS_ERROR_FAILURE;
@@ -2111,8 +2124,10 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
jsval funval = OBJECT_TO_JSVAL(static_cast<JSObject *>(aHandler));
JSAutoRequest ar(mContext);
++mExecuteDepth;
PRBool ok = ::JS_CallFunctionValue(mContext, target,
funval, argc, argv, &rval);
--mExecuteDepth;
if (!ok) {
// Tell XPConnect about any pending exceptions. This is needed
@@ -3498,6 +3513,12 @@ nsJSContext::SetProcessingScriptTag(PRBool aFlag)
mProcessingScriptTag = aFlag;
}
PRBool
nsJSContext::GetExecutingScript()
{
return JS_IsRunning(mContext) || mExecuteDepth > 0;
}
void
nsJSContext::SetGCOnDestruction(PRBool aGCOnDestruction)
{

View File

@@ -149,6 +149,8 @@ public:
virtual PRBool GetProcessingScriptTag();
virtual void SetProcessingScriptTag(PRBool aResult);
virtual PRBool GetExecutingScript();
virtual void SetGCOnDestruction(PRBool aGCOnDestruction);
virtual nsresult InitClasses(void *aGlobalObj);
@@ -292,6 +294,7 @@ private:
PRPackedBool mGCOnDestruction;
PRPackedBool mProcessingScriptTag;
PRUint32 mExecuteDepth;
PRUint32 mDefaultJSOptions;
PRTime mOperationCallbackTime;