Bug 901364 - Implement a replacement operation callback in XPConnect. r=mrbkap

This commit is contained in:
Bobby Holley 2013-08-12 12:54:49 -07:00
parent 962b3d3ad7
commit 2898c52fcd
4 changed files with 73 additions and 0 deletions

View File

@ -39,6 +39,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/Attributes.h"
#include "AccessCheck.h"
#include "nsGlobalWindow.h"
#include "GeckoProfiler.h"
#include "nsJSPrincipals.h"
@ -1228,6 +1229,67 @@ XPCJSRuntime::CTypesActivityCallback(JSContext *cx, js::CTypesActivityType type)
}
}
// static
bool
XPCJSRuntime::OperationCallback(JSContext *cx)
{
XPCJSRuntime *self = XPCJSRuntime::Get();
// If this is the first time the operation callback has fired since we last
// returned to the event loop, mark the checkpoint.
if (self->mSlowScriptCheckpoint.IsNull()) {
self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
return true;
}
// This is at least the second operation callback we've received since
// returning to the event loop. See how long it's been, and what the limit
// is.
TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
bool chrome =
nsContentUtils::IsSystemPrincipal(nsContentUtils::GetSubjectPrincipal());
const char *prefName = chrome ? "dom.max_chrome_script_run_time"
: "dom.max_script_run_time";
int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
// If there's no limit, or we're within the limit, let it go.
if (limit == 0 || duration.ToSeconds() < limit)
return true;
//
// This has gone on long enough! Time to take action. ;-)
//
// Get the DOM window associated with the running script. If the script is
// running in a non-DOM scope, we have to just let it keep running.
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
nsCOMPtr<nsPIDOMWindow> win;
if (IS_WN_REFLECTOR(global))
win = do_QueryWrappedNative(XPCWrappedNative::Get(global));
if (!win)
return true;
// Show the prompt to the user, and kill if requested.
nsGlobalWindow::SlowScriptResponse response =
static_cast<nsGlobalWindow*>(win.get())->ShowSlowScriptDialog();
if (response == nsGlobalWindow::KillSlowScript)
return false;
// The user chose to continue the script. Reset the timer, and disable this
// machinery with a pref of the user opted out of future slow-script dialogs.
self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
if (response == nsGlobalWindow::AlwaysContinueSlowScript)
Preferences::SetInt(prefName, 0);
return true;
}
bool
xpc::OperationCallback(JSContext *cx)
{
return XPCJSRuntime::OperationCallback(cx);
}
size_t
XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
{

View File

@ -1182,6 +1182,9 @@ nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread,
return NS_OK;
mEventDepth--;
// Now that we're back to the event loop, reset the slow script checkpoint.
mRuntime->OnAfterProcessNextEvent();
// Call cycle collector occasionally.
MOZ_ASSERT(NS_IsMainThread());
nsJSContext::MaybePokeCC();

View File

@ -827,6 +827,7 @@ public:
static void ActivityCallback(void *arg, bool active);
static void CTypesActivityCallback(JSContext *cx,
js::CTypesActivityType type);
static bool OperationCallback(JSContext *cx);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
@ -836,6 +837,7 @@ public:
void DeleteJunkScope();
PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory);
void OnAfterProcessNextEvent() { mSlowScriptCheckpoint = mozilla::TimeStamp(); }
private:
XPCJSRuntime(); // no implementation
@ -876,6 +878,8 @@ private:
JSObject* mJunkScope;
nsRefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
mozilla::TimeStamp mSlowScriptCheckpoint;
nsCOMPtr<nsIException> mPendingException;
nsCOMPtr<nsIExceptionManager> mExceptionManager;
bool mExceptionManagerNotAvailable;

View File

@ -67,6 +67,10 @@ AllowXBLScope(JSCompartment *c);
bool
IsSandboxPrototypeProxy(JSObject *obj);
// XXXbholley - Temporary - goes away in future patches.
bool
OperationCallback(JSContext* cx);
} /* namespace xpc */
#define XPCONNECT_GLOBAL_FLAGS \