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:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user