Bug 1016523 - Part 1: Have Debugger treat invoking the interrupt handler as a step in the interpreter. (r=jimb)

This commit is contained in:
Shu-yu Guo 2014-06-05 15:10:32 -07:00
Родитель 20ba3e7f6c
Коммит 61f050f78b
5 изменённых файлов: 64 добавлений и 1 удалений

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

@ -43,6 +43,7 @@
#include "jit/Ion.h"
#endif
#include "js/CharacterEncoding.h"
#include "vm/Debugger.h"
#include "js/OldDebugAPI.h"
#include "vm/HelperThreads.h"
#include "vm/Shape.h"
@ -1032,9 +1033,36 @@ js::InvokeInterruptCallback(JSContext *cx)
// if it re-enters the JS engine. The embedding must ensure that the
// callback is disconnected before attempting such re-entry.
JSInterruptCallback cb = cx->runtime()->interruptCallback;
if (!cb || cb(cx))
if (!cb)
return true;
if (cb(cx)) {
// Debugger treats invoking the interrupt callback as a "step", so
// invoke the onStep handler.
if (cx->compartment()->debugMode()) {
ScriptFrameIter iter(cx);
if (iter.script()->stepModeEnabled()) {
RootedValue rval(cx);
switch (Debugger::onSingleStep(cx, &rval)) {
case JSTRAP_ERROR:
return false;
case JSTRAP_CONTINUE:
return true;
case JSTRAP_RETURN:
// See note in Debugger::propagateForcedReturn.
Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
return false;
case JSTRAP_THROW:
cx->setPendingException(rval);
return false;
default:;
}
}
}
return true;
}
// No need to set aside any pending exception here: ComputeStackString
// already does that.
Rooted<JSString*> stack(cx, ComputeStackString(cx));
@ -1095,6 +1123,7 @@ JSContext::JSContext(JSRuntime *rt)
throwing(false),
unwrappedException_(UndefinedValue()),
options_(),
propagatingForcedReturn_(false),
reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
resolvingList(nullptr),
generatingError(false),

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

@ -422,6 +422,10 @@ struct JSContext : public js::ExclusiveContext,
/* Per-context options. */
JS::ContextOptions options_;
// True if propagating a forced return from an interrupt handler during
// debug mode.
bool propagatingForcedReturn_;
public:
int32_t reportGranularity; /* see vm/Probes.h */
@ -570,6 +574,10 @@ struct JSContext : public js::ExclusiveContext,
unwrappedException_.setUndefined();
}
bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
#ifdef DEBUG
/*
* Controls whether a quadratic-complexity assertion is performed during

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

@ -3676,6 +3676,23 @@ Debugger::handleIonBailout(JSContext *cx, jit::RematerializedFrame *from, jit::B
return replaceFrameGuts(cx, from, to, iter);
}
/* static */ void
Debugger::propagateForcedReturn(JSContext *cx, AbstractFramePtr frame, HandleValue rval)
{
// Invoking the interrupt handler is considered a step and invokes the
// youngest frame's onStep handler, if any. However, we cannot handle
// { return: ... } resumption values straightforwardly from the interrupt
// handler. Instead, we set the intended return value in the frame's rval
// slot and set the propagating-forced-return flag on the JSContext.
//
// The interrupt handler then returns false with no exception set,
// signaling an uncatchable exception. In the exception handlers, we then
// check for the special propagating-forced-return flag.
MOZ_ASSERT(!cx->isExceptionPending());
cx->setPropagatingForcedReturn();
frame.setReturnValue(rval);
}
static bool
DebuggerScript_setBreakpoint(JSContext *cx, unsigned argc, Value *vp)
{

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

@ -442,6 +442,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
static JSTrapStatus onSingleStep(JSContext *cx, MutableHandleValue vp);
static bool handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to);
static bool handleIonBailout(JSContext *cx, jit::RematerializedFrame *from, jit::BaselineFrame *to);
static void propagateForcedReturn(JSContext *cx, AbstractFramePtr frame, HandleValue rval);
/************************************* Functions for use by Debugger.cpp. */

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

@ -1054,6 +1054,14 @@ HandleError(JSContext *cx, InterpreterRegs &regs)
}
}
} else {
// We may be propagating a forced return from the interrupt
// callback, which cannot easily force a return.
if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) {
cx->clearPropagatingForcedReturn();
ForcedReturn(cx, si, regs);
return SuccessfulReturnContinuation;
}
UnwindForUncatchableException(cx, regs);
}