зеркало из https://github.com/mozilla/gecko-dev.git
Bug 716647 - Part 6 1/2: Add shell function to deterministically request interrupt. (r=jimb)
This commit is contained in:
Родитель
7cec2c2638
Коммит
cb89c61677
|
@ -2,18 +2,22 @@
|
|||
|
||||
load(libdir + "jitopts.js");
|
||||
|
||||
if (!jitTogglesMatch(Opts_Ion2NoParallelCompilation))
|
||||
if (!jitTogglesMatch(Opts_IonEagerNoParallelCompilation))
|
||||
quit(0);
|
||||
|
||||
withJitOptions(Opts_Ion2NoParallelCompilation, function () {
|
||||
withJitOptions(Opts_IonEagerNoParallelCompilation, function () {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
|
||||
g.eval("" + function f(d) { g(d); });
|
||||
g.eval("" + function g(d) { h(d); });
|
||||
g.eval("" + function h(d) { while (d); });
|
||||
g.eval("" + function h(d) {
|
||||
var i = 0;
|
||||
while (d)
|
||||
interruptIf(d && i++ == 4000);
|
||||
});
|
||||
|
||||
timeout(5, function () {
|
||||
setInterruptCallback(function () {
|
||||
dbg.addDebuggee(g);
|
||||
var frame = dbg.getNewestFrame();
|
||||
if (frame.callee.name != "h" || frame.implementation != "ion")
|
||||
|
|
|
@ -112,8 +112,8 @@ static size_t gMaxStackSize = 128 * sizeof(size_t) * 1024;
|
|||
*/
|
||||
static double MAX_TIMEOUT_INTERVAL = 1800.0;
|
||||
static double gTimeoutInterval = -1.0;
|
||||
static volatile bool gTimedOut = false;
|
||||
static Maybe<JS::PersistentRootedValue> gTimeoutFunc;
|
||||
static volatile bool gServiceInterrupt = false;
|
||||
static Maybe<JS::PersistentRootedValue> gInterruptFunc;
|
||||
|
||||
static bool enableDisassemblyDumps = false;
|
||||
|
||||
|
@ -335,7 +335,7 @@ static JSShellContextData *
|
|||
NewContextData()
|
||||
{
|
||||
/* Prevent creation of new contexts after we have been canceled. */
|
||||
if (gTimedOut)
|
||||
if (gServiceInterrupt)
|
||||
return nullptr;
|
||||
|
||||
JSShellContextData *data = (JSShellContextData *)
|
||||
|
@ -358,16 +358,16 @@ GetContextData(JSContext *cx)
|
|||
static bool
|
||||
ShellInterruptCallback(JSContext *cx)
|
||||
{
|
||||
if (!gTimedOut)
|
||||
if (!gServiceInterrupt)
|
||||
return true;
|
||||
|
||||
bool result;
|
||||
RootedValue timeoutFunc(cx, gTimeoutFunc.ref());
|
||||
if (!timeoutFunc.isNull()) {
|
||||
RootedValue interruptFunc(cx, gInterruptFunc.ref());
|
||||
if (!interruptFunc.isNull()) {
|
||||
JS::AutoSaveExceptionState savedExc(cx);
|
||||
JSAutoCompartment ac(cx, &timeoutFunc.toObject());
|
||||
JSAutoCompartment ac(cx, &interruptFunc.toObject());
|
||||
RootedValue rval(cx);
|
||||
if (!JS_CallFunctionValue(cx, JS::NullPtr(), timeoutFunc,
|
||||
if (!JS_CallFunctionValue(cx, JS::NullPtr(), interruptFunc,
|
||||
JS::HandleValueArray::empty(), &rval))
|
||||
{
|
||||
return false;
|
||||
|
@ -451,7 +451,7 @@ RunFile(JSContext *cx, Handle<JSObject*> obj, const char *filename, FILE *file,
|
|||
#endif
|
||||
if (script && !compileOnly) {
|
||||
if (!JS_ExecuteScript(cx, obj, script)) {
|
||||
if (!gQuitting && !gTimedOut)
|
||||
if (!gQuitting && !gServiceInterrupt)
|
||||
gExitCode = EXITCODE_RUNTIME_ERROR;
|
||||
}
|
||||
int64_t t2 = PRMJ_Now() - t1;
|
||||
|
@ -514,7 +514,7 @@ ReadEvalPrintLoop(JSContext *cx, Handle<JSObject*> global, FILE *in, FILE *out,
|
|||
CharBuffer buffer(cx);
|
||||
do {
|
||||
ScheduleWatchdog(cx->runtime(), -1);
|
||||
gTimedOut = false;
|
||||
gServiceInterrupt = false;
|
||||
errno = 0;
|
||||
|
||||
char *line = GetLine(in, startline == lineno ? "js> " : "");
|
||||
|
@ -3081,7 +3081,7 @@ Sleep_fn(JSContext *cx, unsigned argc, Value *vp)
|
|||
int64_t to_wakeup = PRMJ_Now() + t_ticks;
|
||||
for (;;) {
|
||||
PR_WaitCondVar(gSleepWakeup, t_ticks);
|
||||
if (gTimedOut)
|
||||
if (gServiceInterrupt)
|
||||
break;
|
||||
int64_t now = PRMJ_Now();
|
||||
if (!IsBefore(now, to_wakeup))
|
||||
|
@ -3089,7 +3089,7 @@ Sleep_fn(JSContext *cx, unsigned argc, Value *vp)
|
|||
t_ticks = to_wakeup - now;
|
||||
}
|
||||
PR_Unlock(gWatchdogLock);
|
||||
return !gTimedOut;
|
||||
return !gServiceInterrupt;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -3281,10 +3281,10 @@ ScheduleWatchdog(JSRuntime *rt, double t)
|
|||
static void
|
||||
CancelExecution(JSRuntime *rt)
|
||||
{
|
||||
gTimedOut = true;
|
||||
gServiceInterrupt = true;
|
||||
JS_RequestInterruptCallback(rt);
|
||||
|
||||
if (!gTimeoutFunc.ref().get().isNull()) {
|
||||
if (!gInterruptFunc.ref().get().isNull()) {
|
||||
static const char msg[] = "Script runs for too long, terminating.\n";
|
||||
#if defined(XP_UNIX) && !defined(JS_THREADSAFE)
|
||||
/* It is not safe to call fputs from signals. */
|
||||
|
@ -3338,13 +3338,53 @@ Timeout(JSContext *cx, unsigned argc, Value *vp)
|
|||
JS_ReportError(cx, "Second argument must be a timeout function");
|
||||
return false;
|
||||
}
|
||||
gTimeoutFunc.ref() = value;
|
||||
gInterruptFunc.ref() = value;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return SetTimeoutValue(cx, t);
|
||||
}
|
||||
|
||||
static bool
|
||||
InterruptIf(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() != 1) {
|
||||
JS_ReportError(cx, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ToBoolean(args[0])) {
|
||||
gServiceInterrupt = true;
|
||||
JS_RequestInterruptCallback(cx->runtime());
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
SetInterruptCallback(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() != 1) {
|
||||
JS_ReportError(cx, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue value(cx, args[0]);
|
||||
if (!value.isObject() || !value.toObject().is<JSFunction>()) {
|
||||
JS_ReportError(cx, "Argument must be a function");
|
||||
return false;
|
||||
}
|
||||
gInterruptFunc.ref() = value;
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
Elapsed(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
|
@ -4598,7 +4638,18 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
|
|||
"timeout([seconds], [func])",
|
||||
" Get/Set the limit in seconds for the execution time for the current context.\n"
|
||||
" A negative value (default) means that the execution time is unlimited.\n"
|
||||
" If a second argument is provided, it will be invoked when the timer elapses.\n"),
|
||||
" If a second argument is provided, it will be invoked when the timer elapses.\n"
|
||||
" Calling this function will replace any callback set by |setInterruptCallback|.\n"),
|
||||
|
||||
JS_FN_HELP("interruptIf", InterruptIf, 1, 0,
|
||||
"interruptIf(cond)",
|
||||
" Requests interrupt callback if cond is true. If a callback function is set via\n"
|
||||
" |timeout| or |setInterruptCallback|, it will be called. No-op otherwise."),
|
||||
|
||||
JS_FN_HELP("setInterruptCallback", SetInterruptCallback, 1, 0,
|
||||
"setInterruptCallback(func)",
|
||||
" Sets func as the interrupt callback function.\n"
|
||||
" Calling this function will replace any callback set by |timeout|.\n"),
|
||||
|
||||
JS_FN_HELP("elapsed", Elapsed, 0, 0,
|
||||
"elapsed()",
|
||||
|
@ -6134,7 +6185,7 @@ main(int argc, char **argv, char **envp)
|
|||
if (!SetRuntimeOptions(rt, op))
|
||||
return 1;
|
||||
|
||||
gTimeoutFunc.construct(rt, NullValue());
|
||||
gInterruptFunc.construct(rt, NullValue());
|
||||
|
||||
JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
|
@ -6184,7 +6235,7 @@ main(int argc, char **argv, char **envp)
|
|||
|
||||
KillWatchdog();
|
||||
|
||||
gTimeoutFunc.destroy();
|
||||
gInterruptFunc.destroy();
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
for (size_t i = 0; i < workerThreads.length(); i++)
|
||||
|
|
Загрузка…
Ссылка в новой задаче