This commit is contained in:
Shu-yu Guo 2014-06-05 15:10:33 -07:00
Родитель fab1415209
Коммит f8895f4b71
4 изменённых файлов: 103 добавлений и 1 удалений

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

@ -0,0 +1,55 @@
// Test that invoking the interrupt callback counts as a step.
function testResumptionVal(resumptionVal, turnOffDebugMode) {
var g = newGlobal();
var dbg = new Debugger;
g.log = "";
g.resumptionVal = resumptionVal;
setInterruptCallback(function () {
g.log += "i";
dbg.addDebuggee(g);
var frame = dbg.getNewestFrame();
frame.onStep = function () {
g.log += "s";
frame.onStep = undefined;
if (turnOffDebugMode)
dbg.removeDebuggee(g);
return resumptionVal;
};
return true;
});
try {
return g.eval("(" + function f() {
log += "f";
invokeInterruptCallback(function (interruptRv) {
log += "r";
assertEq(interruptRv, resumptionVal == undefined);
});
log += "a";
return 42;
} + ")();");
} finally {
assertEq(g.log, resumptionVal == undefined ? "fisra" : "fisr");
}
}
assertEq(testResumptionVal(undefined), 42);
assertEq(testResumptionVal({ return: "not 42" }), "not 42");
try {
testResumptionVal({ throw: "thrown 42" });
} catch (e) {
assertEq(e, "thrown 42");
}
assertEq(testResumptionVal(undefined, true), 42);
assertEq(testResumptionVal({ return: "not 42" }, true), "not 42");
try {
testResumptionVal({ throw: "thrown 42" }, true);
} catch (e) {
assertEq(e, "thrown 42");
}

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

@ -6090,10 +6090,15 @@ JS_ReportPendingException(JSContext *cx)
}
JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext *cx)
: context(cx), wasThrowing(cx->throwing), exceptionValue(cx)
: context(cx),
wasPropagatingForcedReturn(cx->propagatingForcedReturn_),
wasThrowing(cx->throwing),
exceptionValue(cx)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
if (wasPropagatingForcedReturn)
cx->clearPropagatingForcedReturn();
if (wasThrowing) {
exceptionValue = cx->unwrappedException_;
cx->clearPendingException();
@ -6103,6 +6108,7 @@ JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext *cx)
void
JS::AutoSaveExceptionState::restore()
{
context->propagatingForcedReturn_ = wasPropagatingForcedReturn;
context->throwing = wasThrowing;
context->unwrappedException_ = exceptionValue;
drop();
@ -6110,6 +6116,8 @@ JS::AutoSaveExceptionState::restore()
JS::AutoSaveExceptionState::~AutoSaveExceptionState()
{
if (wasPropagatingForcedReturn && !context->isPropagatingForcedReturn())
context->setPropagatingForcedReturn();
if (wasThrowing && !context->isExceptionPending()) {
context->throwing = true;
context->unwrappedException_ = exceptionValue;

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

@ -4660,6 +4660,7 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
{
private:
JSContext *context;
bool wasPropagatingForcedReturn;
bool wasThrowing;
RootedValue exceptionValue;
@ -4681,6 +4682,7 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
* If this is called, the destructor is a no-op.
*/
void drop() {
wasPropagatingForcedReturn = false;
wasThrowing = false;
exceptionValue.setUndefined();
}

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

@ -3425,6 +3425,36 @@ InterruptIf(JSContext *cx, unsigned argc, Value *vp)
return true;
}
static bool
InvokeInterruptCallbackWrapper(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1) {
JS_ReportError(cx, "Wrong number of arguments");
return false;
}
gServiceInterrupt = true;
JS_RequestInterruptCallback(cx->runtime());
bool interruptRv = CheckForInterrupt(cx);
// The interrupt handler could have set a pending exception. Since we call
// back into JS, don't have it see the pending exception. If we have an
// uncatchable exception that's not propagating a debug mode forced
// return, return.
if (!interruptRv && !cx->isExceptionPending() && !cx->isPropagatingForcedReturn())
return false;
JS::AutoSaveExceptionState savedExc(cx);
Value argv[1] = { BooleanValue(interruptRv) };
RootedValue rv(cx);
if (!Invoke(cx, UndefinedValue(), args[0], 1, argv, &rv))
return false;
args.rval().setUndefined();
return interruptRv;
}
static bool
SetInterruptCallback(JSContext *cx, unsigned argc, Value *vp)
{
@ -4728,6 +4758,13 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
" 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("invokeInterruptCallback", InvokeInterruptCallbackWrapper, 0, 0,
"invokeInterruptCallback(fun)",
" Forcefully set the interrupt flag and invoke the interrupt handler. If a\n"
" callback function is set via |timeout| or |setInterruptCallback|, it will\n"
" be called. Before returning, fun is called with the return value of the\n"
" interrupt handler."),
JS_FN_HELP("setInterruptCallback", SetInterruptCallback, 1, 0,
"setInterruptCallback(func)",
" Sets func as the interrupt callback function.\n"