Bug 1279086 - Allow multiple interrupt callbacks (r=dvander)

This commit is contained in:
Bill McCloskey 2016-06-23 17:03:03 -07:00
Родитель 1d37a92675
Коммит a51047b439
10 изменённых файлов: 40 добавлений и 24 удалений

Просмотреть файл

@ -11154,14 +11154,14 @@ nsGlobalWindow::ShowSlowScriptDialog()
buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2; buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
// Null out the operation callback while we're re-entering JS here. // Null out the operation callback while we're re-entering JS here.
JSInterruptCallback old = JS_SetInterruptCallback(cx, nullptr); bool old = JS_DisableInterruptCallback(cx);
// Open the dialog. // Open the dialog.
rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton, rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
debugButton, neverShowDlg, &neverShowDlgChk, debugButton, neverShowDlg, &neverShowDlgChk,
&buttonPressed); &buttonPressed);
JS_SetInterruptCallback(cx, old); JS_ResetInterruptCallback(cx, old);
if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) { if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript; return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;

Просмотреть файл

@ -994,7 +994,7 @@ InitJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSContext* aWorkerCx)
return false; return false;
} }
JS_SetInterruptCallback(aWorkerCx, InterruptCallback); JS_AddInterruptCallback(aWorkerCx, InterruptCallback);
js::SetCTypesActivityCallback(aWorkerCx, CTypesActivityCallback); js::SetCTypesActivityCallback(aWorkerCx, CTypesActivityCallback);

Просмотреть файл

@ -24,7 +24,7 @@ RequestInterruptCallback(JSContext* cx, unsigned argc, jsval* vp)
BEGIN_TEST(testSlowScript) BEGIN_TEST(testSlowScript)
{ {
JS_SetInterruptCallback(cx, InterruptCallback); JS_AddInterruptCallback(cx, InterruptCallback);
JS_DefineFunction(cx, global, "requestInterruptCallback", RequestInterruptCallback, 0, 0); JS_DefineFunction(cx, global, "requestInterruptCallback", RequestInterruptCallback, 0, 0);
test("while (true)" test("while (true)"

Просмотреть файл

@ -4617,18 +4617,24 @@ JS_CheckForInterrupt(JSContext* cx)
return js::CheckForInterrupt(cx); return js::CheckForInterrupt(cx);
} }
JS_PUBLIC_API(JSInterruptCallback) JS_PUBLIC_API(bool)
JS_SetInterruptCallback(JSContext* cx, JSInterruptCallback callback) JS_AddInterruptCallback(JSContext* cx, JSInterruptCallback callback)
{ {
JSInterruptCallback old = cx->interruptCallback; return cx->interruptCallbacks.append(callback);
cx->interruptCallback = callback;
return old;
} }
JS_PUBLIC_API(JSInterruptCallback) JS_PUBLIC_API(bool)
JS_GetInterruptCallback(JSContext* cx) JS_DisableInterruptCallback(JSContext* cx)
{ {
return cx->interruptCallback; bool result = cx->interruptCallbackDisabled;
cx->interruptCallbackDisabled = true;
return result;
}
JS_PUBLIC_API(void)
JS_ResetInterruptCallback(JSContext* cx, bool enable)
{
cx->interruptCallbackDisabled = enable;
} }
/************************************************************************/ /************************************************************************/

Просмотреть файл

@ -4305,11 +4305,14 @@ JS_CheckForInterrupt(JSContext* cx);
* if it re-enters the JS engine. The embedding must ensure that the callback * if it re-enters the JS engine. The embedding must ensure that the callback
* is disconnected before attempting such re-entry. * is disconnected before attempting such re-entry.
*/ */
extern JS_PUBLIC_API(JSInterruptCallback) extern JS_PUBLIC_API(bool)
JS_SetInterruptCallback(JSContext* cx, JSInterruptCallback callback); JS_AddInterruptCallback(JSContext* cx, JSInterruptCallback callback);
extern JS_PUBLIC_API(JSInterruptCallback) extern JS_PUBLIC_API(bool)
JS_GetInterruptCallback(JSContext* cx); JS_DisableInterruptCallback(JSContext* cx);
extern JS_PUBLIC_API(void)
JS_ResetInterruptCallback(JSContext* cx, bool enable);
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
JS_RequestInterruptCallback(JSContext* cx); JS_RequestInterruptCallback(JSContext* cx);

Просмотреть файл

@ -7623,7 +7623,7 @@ main(int argc, char** argv, char** envp)
JS_SetSecurityCallbacks(cx, &ShellPrincipals::securityCallbacks); JS_SetSecurityCallbacks(cx, &ShellPrincipals::securityCallbacks);
JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy); JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
JS_SetInterruptCallback(cx, ShellInterruptCallback); JS_AddInterruptCallback(cx, ShellInterruptCallback);
JS::SetBuildIdOp(cx, ShellBuildId); JS::SetBuildIdOp(cx, ShellBuildId);
JS::SetAsmJSCacheOps(cx, &asmJSCacheOps); JS::SetAsmJSCacheOps(cx, &asmJSCacheOps);

Просмотреть файл

@ -149,7 +149,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
telemetryCallback(nullptr), telemetryCallback(nullptr),
handlingSegFault(false), handlingSegFault(false),
handlingJitInterrupt_(false), handlingJitInterrupt_(false),
interruptCallback(nullptr), interruptCallbackDisabled(false),
getIncumbentGlobalCallback(nullptr), getIncumbentGlobalCallback(nullptr),
enqueuePromiseJobCallback(nullptr), enqueuePromiseJobCallback(nullptr),
enqueuePromiseJobCallbackData(nullptr), enqueuePromiseJobCallbackData(nullptr),
@ -530,11 +530,16 @@ InvokeInterruptCallback(JSContext* cx)
// Important: Additional callbacks can occur inside the callback handler // Important: Additional callbacks can occur inside the callback handler
// if it re-enters the JS engine. The embedding must ensure that the // if it re-enters the JS engine. The embedding must ensure that the
// callback is disconnected before attempting such re-entry. // callback is disconnected before attempting such re-entry.
JSInterruptCallback cb = cx->runtime()->interruptCallback; if (cx->runtime()->interruptCallbackDisabled)
if (!cb)
return true; return true;
if (cb(cx)) { bool stop = false;
for (JSInterruptCallback cb : cx->runtime()->interruptCallbacks) {
if (!cb(cx))
stop = true;
}
if (!stop) {
// Debugger treats invoking the interrupt callback as a "step", so // Debugger treats invoking the interrupt callback as a "step", so
// invoke the onStep handler. // invoke the onStep handler.
if (cx->compartment()->isDebuggee()) { if (cx->compartment()->isDebuggee()) {

Просмотреть файл

@ -638,7 +638,9 @@ struct JSRuntime : public JS::shadow::Runtime,
return handlingJitInterrupt_; return handlingJitInterrupt_;
} }
JSInterruptCallback interruptCallback; using InterruptCallbackVector = js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
InterruptCallbackVector interruptCallbacks;
bool interruptCallbackDisabled;
JSGetIncumbentGlobalCallback getIncumbentGlobalCallback; JSGetIncumbentGlobalCallback getIncumbentGlobalCallback;
JSEnqueuePromiseJobCallback enqueuePromiseJobCallback; JSEnqueuePromiseJobCallback enqueuePromiseJobCallback;

Просмотреть файл

@ -3476,7 +3476,7 @@ XPCJSContext::Initialize()
#endif #endif
JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback); JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback);
js::SetActivityCallback(cx, ActivityCallback, this); js::SetActivityCallback(cx, ActivityCallback, this);
JS_SetInterruptCallback(cx, InterruptCallback); JS_AddInterruptCallback(cx, InterruptCallback);
js::SetWindowProxyClass(cx, &OuterWindowProxyClass); js::SetWindowProxyClass(cx, &OuterWindowProxyClass);
// The JS engine needs to keep the source code around in order to implement // The JS engine needs to keep the source code around in order to implement

Просмотреть файл

@ -1421,7 +1421,7 @@ XRE_XPCShellMain(int argc, char** argv, char** envp,
sScriptedInterruptCallback = new PersistentRootedValue; sScriptedInterruptCallback = new PersistentRootedValue;
sScriptedInterruptCallback->init(cx, UndefinedValue()); sScriptedInterruptCallback->init(cx, UndefinedValue());
JS_SetInterruptCallback(cx, XPCShellInterruptCallback); JS_AddInterruptCallback(cx, XPCShellInterruptCallback);
argc--; argc--;
argv++; argv++;