Bug 1125120 - Clean up Debugger.Frames when the debug mode in-place Ion bailout fails. (r=jandem)

This commit is contained in:
Shu-yu Guo 2015-01-27 17:06:24 -08:00
Родитель 4e73ce230d
Коммит e8bafaf621
5 изменённых файлов: 69 добавлений и 26 удалений

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

@ -389,10 +389,10 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx
// debuggee of a Debugger with a live onExceptionUnwind hook, or if a
// Debugger has observed this frame (e.g., for onPop).
bool shouldBail = Debugger::hasLiveHook(cx->global(), Debugger::OnExceptionUnwind);
RematerializedFrame *rematFrame = nullptr;
if (!shouldBail) {
JitActivation *act = cx->runtime()->activation()->asJit();
RematerializedFrame *rematFrame =
act->lookupRematerializedFrame(frame.frame().fp(), frame.frameNo());
rematFrame = act->lookupRematerializedFrame(frame.frame().fp(), frame.frameNo());
shouldBail = rematFrame && rematFrame->isDebuggee();
}
@ -414,7 +414,19 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx
uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed);
if (retval == BAILOUT_RETURN_OK)
return;
// If bailout failed (e.g., due to overrecursion), clean up any
// Debugger.Frame instances here. Normally this should happen
// inside the debug epilogue, but due to bailout failure, we
// cannot honor any Debugger hooks.
if (rematFrame)
Debugger::handleUnrecoverableIonBailoutError(cx, rematFrame);
}
#ifdef DEBUG
if (rematFrame)
Debugger::assertNotInFrameMaps(rematFrame);
#endif
}
if (!script->hasTrynotes())

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

@ -8,6 +8,7 @@
#include "jit/JitFrames.h"
#include "vm/ArgumentsObject.h"
#include "vm/Debugger.h"
#include "jsscriptinlines.h"
#include "jit/JitFrames-inl.h"
@ -95,6 +96,7 @@ RematerializedFrame::FreeInVector(Vector<RematerializedFrame *> &frames)
{
for (size_t i = 0; i < frames.length(); i++) {
RematerializedFrame *f = frames[i];
Debugger::assertNotInFrameMaps(f);
f->RematerializedFrame::~RematerializedFrame();
js_free(f);
}

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

@ -22,6 +22,7 @@ js::Debugger::onLeaveFrame(JSContext *cx, AbstractFramePtr frame, bool ok)
MOZ_ASSERT_IF(evalTraps, frame.isDebuggee());
if (frame.isDebuggee())
ok = slowPathOnLeaveFrame(cx, frame, ok);
assertNotInFrameMaps(frame);
return ok;
}

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

@ -664,30 +664,11 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx, AbstractFramePtr frame, bool frame
}
/*
* Clean up all Debugger.Frame instances. Use a fresh FrameRange, as one
* debugger's onPop handler could have caused another debugger to create its
* own Debugger.Frame instance.
* Clean up all Debugger.Frame instances. This call creates a fresh
* FrameRange, as one debugger's onPop handler could have caused another
* debugger to create its own Debugger.Frame instance.
*/
for (FrameRange r(frame, global); !r.empty(); r.popFront()) {
RootedNativeObject frameobj(cx, r.frontFrame());
Debugger *dbg = r.frontDebugger();
MOZ_ASSERT(dbg == Debugger::fromChildJSObject(frameobj));
FreeOp *fop = cx->runtime()->defaultFreeOp();
DebuggerFrame_freeScriptFrameIterData(fop, frameobj);
DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, frame, frameobj);
dbg->frames.remove(frame);
}
/*
* If this is an eval frame, then from the debugger's perspective the
* script is about to be destroyed. Remove any breakpoints in it.
*/
if (frame.isEvalFrame()) {
RootedScript script(cx, frame.script());
script->clearBreakpointsIn(cx->runtime()->defaultFreeOp(), nullptr, nullptr);
}
removeFromFrameMapsAndClearBreakpointsIn(cx, frame);
/* Establish (status, value) as our resumption value. */
switch (status) {
@ -4866,6 +4847,42 @@ Debugger::replaceFrameGuts(JSContext *cx, AbstractFramePtr from, AbstractFramePt
return true;
}
/* static */ void
Debugger::assertNotInFrameMaps(AbstractFramePtr frame)
{
#ifdef DEBUG
FrameRange r(frame);
MOZ_ASSERT(r.empty());
#endif
}
/* static */ void
Debugger::removeFromFrameMapsAndClearBreakpointsIn(JSContext *cx, AbstractFramePtr frame)
{
Handle<GlobalObject *> global = cx->global();
for (FrameRange r(frame, global); !r.empty(); r.popFront()) {
RootedNativeObject frameobj(cx, r.frontFrame());
Debugger *dbg = r.frontDebugger();
MOZ_ASSERT(dbg == Debugger::fromChildJSObject(frameobj));
FreeOp *fop = cx->runtime()->defaultFreeOp();
DebuggerFrame_freeScriptFrameIterData(fop, frameobj);
DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, frame, frameobj);
dbg->frames.remove(frame);
}
/*
* If this is an eval frame, then from the debugger's perspective the
* script is about to be destroyed. Remove any breakpoints in it.
*/
if (frame.isEvalFrame()) {
RootedScript script(cx, frame.script());
script->clearBreakpointsIn(cx->runtime()->defaultFreeOp(), nullptr, nullptr);
}
}
/* static */ bool
Debugger::handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to)
{
@ -4891,6 +4908,15 @@ Debugger::handleIonBailout(JSContext *cx, jit::RematerializedFrame *from, jit::B
return replaceFrameGuts(cx, from, to, iter);
}
/* static */ void
Debugger::handleUnrecoverableIonBailoutError(JSContext *cx, jit::RematerializedFrame *frame)
{
// Ion bailout can fail due to overrecursion. In such cases we cannot
// honor any further Debugger hooks on the frame, and need to ensure that
// its Debugger.Frame entry is cleaned up.
removeFromFrameMapsAndClearBreakpointsIn(cx, frame);
}
/* static */ void
Debugger::propagateForcedReturn(JSContext *cx, AbstractFramePtr frame, HandleValue rval)
{

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

@ -425,7 +425,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static bool getNewestAbstractFramePtr(JSContext *cx);
static void removeFromFrameMapsAndClearBreakpointsIn(JSContext *cx, AbstractFramePtr frame);
static bool updateExecutionObservabilityOfFrames(JSContext *cx, const ExecutionObservableSet &obs,
IsObserving observing);
static bool updateExecutionObservabilityOfScripts(JSContext *cx, const ExecutionObservableSet &obs,
@ -607,8 +607,10 @@ 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 handleUnrecoverableIonBailoutError(JSContext *cx, jit::RematerializedFrame *frame);
static void propagateForcedReturn(JSContext *cx, AbstractFramePtr frame, HandleValue rval);
static bool hasLiveHook(GlobalObject *global, Hook which);
static void assertNotInFrameMaps(AbstractFramePtr frame);
/************************************* Functions for use by Debugger.cpp. */