зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1016523 - Part 1: Have Debugger treat invoking the interrupt handler as a step in the interpreter. (r=jimb)
This commit is contained in:
Родитель
20ba3e7f6c
Коммит
61f050f78b
|
@ -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 ®s)
|
|||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче