From cafa975bba6a4756feb9d0c813dcf3c3cba3acbd Mon Sep 17 00:00:00 2001 From: "jst%netscape.com" Date: Sat, 24 Jun 2000 16:18:41 +0000 Subject: [PATCH] Fixing nsbeta2+ bug 13350, add a JS branch callback to the DOM code that runs the JS GC and also lets users abort extremely long running scripts (i.e. infinite JS loops). r=vidur&brendan git-svn-id: svn://10.0.0.236/trunk@73170 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/dom/src/base/nsJSEnvironment.cpp | 62 ++++++++++++++++++++++++ mozilla/dom/src/base/nsJSEnvironment.h | 3 ++ 2 files changed, 65 insertions(+) diff --git a/mozilla/dom/src/base/nsJSEnvironment.cpp b/mozilla/dom/src/base/nsJSEnvironment.cpp index aa95ddb046d..200a87f2543 100644 --- a/mozilla/dom/src/base/nsJSEnvironment.cpp +++ b/mozilla/dom/src/base/nsJSEnvironment.cpp @@ -49,6 +49,8 @@ #include "nsJSUtils.h" #include "nsIDocShell.h" #include "nsIPresContext.h" +#include "nsIInterfaceRequestor.h" +#include "nsIPrompt.h" #include "nsIObserverService.h" // Force PR_LOGGING so we can get JS strict warnings even in release builds @@ -188,6 +190,61 @@ NS_ScriptErrorReporter(JSContext *cx, ::JS_ClearPendingException(cx); } +#define MAYBE_GC_BRANCH_COUNT_MASK 0x00000fff // 4095 +#define MAYBE_STOP_BRANCH_COUNT_MASK 0x003fffff + +JSBool PR_CALLBACK +nsJSContext::DOMBranchCallback(JSContext *cx, JSScript *script) +{ + // Get the native context + nsJSContext *ctx = (nsJSContext *)::JS_GetContextPrivate(cx); + NS_ENSURE_TRUE(ctx, JS_TRUE); + + // Filter out most of the calls to this callback + if (++ctx->mBranchCallbackCount & MAYBE_GC_BRANCH_COUNT_MASK) + return JS_TRUE; + + // Run the GC if we get this far. + JS_MaybeGC(cx); + + // Filter out most of the calls to this callback that make it this far + if (ctx->mBranchCallbackCount & MAYBE_STOP_BRANCH_COUNT_MASK) + return JS_TRUE; + + // If we get here we're most likely executing an infinite loop in JS, + // we'll tell the user about this and we'll give the user the option + // of stopping the execution of the script. + nsCOMPtr global(dont_AddRef(ctx->GetGlobalObject())); + NS_ENSURE_TRUE(global, JS_TRUE); + + nsCOMPtr docShell; + global->GetDocShell(getter_AddRefs(docShell)); + NS_ENSURE_TRUE(docShell, JS_TRUE); + + nsCOMPtr ireq(do_QueryInterface(docShell)); + NS_ENSURE_TRUE(ireq, JS_TRUE); + + // Get the nsIPrompt interface from the docshell + nsCOMPtr prompt; + ireq->GetInterface(NS_GET_IID(nsIPrompt), getter_AddRefs(prompt)); + NS_ENSURE_TRUE(prompt, JS_TRUE); + + nsAutoString title, msg; + title.AssignWithConversion("Script warning"); + msg.AssignWithConversion("A script on this page is causing mozilla to " + "run slowly. If it continues to run, your " + "computer may become unresponsive.\n\nDo you " + "want to abort the script?"); + + JSBool ret = JS_TRUE; + + // Open the dialog. + if (NS_FAILED(prompt->Confirm(title.GetUnicode(), msg.GetUnicode(), &ret))) + return JS_TRUE; + + return !ret; +} + nsJSContext::nsJSContext(JSRuntime *aRuntime) { NS_INIT_REFCNT(); @@ -219,6 +276,8 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) if (options) ::JS_SetOptions(mContext, options); } + + ::JS_SetBranchCallback(mContext, DOMBranchCallback); } mIsInitialized = PR_FALSE; mNumEvaluations = 0; @@ -226,6 +285,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) mOwner = nsnull; mTerminationFunc = nsnull; mScriptsEnabled = PR_TRUE; + mBranchCallbackCount = 0; } const char kScriptSecurityManagerProgID[] = NS_SCRIPTSECURITYMANAGER_PROGID; @@ -1083,6 +1143,8 @@ nsJSContext::ScriptEvaluated(void) ::JS_MaybeGC(mContext); } + mBranchCallbackCount = 0; + return NS_OK; } diff --git a/mozilla/dom/src/base/nsJSEnvironment.h b/mozilla/dom/src/base/nsJSEnvironment.h index 6bea3212cf2..3ce938acfb7 100644 --- a/mozilla/dom/src/base/nsJSEnvironment.h +++ b/mozilla/dom/src/base/nsJSEnvironment.h @@ -48,6 +48,9 @@ private: nsScriptTerminationFunc mTerminationFunc; nsCOMPtr mRef; PRBool mScriptsEnabled; + PRUint32 mBranchCallbackCount; + + static JSBool PR_CALLBACK DOMBranchCallback(JSContext *cx, JSScript *script); public: nsJSContext(JSRuntime *aRuntime);