зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1016523 - Test. (r=jimb)
This commit is contained in:
Родитель
fab1415209
Коммит
f8895f4b71
|
@ -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"
|
||||
|
|
Загрузка…
Ссылка в новой задаче