Bug 749697 - Support debugging when multiple JSContexts are on the stack. Part 2, fix evcross-context eval-in-frame. r=luke.

--HG--
extra : rebase_source : 216bdac31ec88af4130ffd9ffac9bf0ebb1a9b39
This commit is contained in:
Jason Orendorff 2012-05-17 18:57:34 -05:00
parent 617373c265
commit 1eb2ec4e0b
4 changed files with 71 additions and 5 deletions

View File

@ -0,0 +1,20 @@
// frame.eval can evaluate code in a frame pushed in another context. Bug 749697.
// In other words, the debugger can see all frames on the stack, even though
// each frame is attached to a particular JSContext and multiple JSContexts may
// have frames on the stack.
var g = newGlobal('new-compartment');
g.eval('function f(a) { debugger; evaluate("debugger;", {newContext: true}); }');
var dbg = new Debugger(g);
var hits = 0;
dbg.onDebuggerStatement = function (frame1) {
dbg.onDebuggerStatement = function (frame2) {
assertEq(frame1.eval("a").return, 31);
hits++;
};
};
g.f(31);
assertEq(hits, 1);

View File

@ -0,0 +1,32 @@
// The debugger can eval in any frame in the stack even if every frame was
// pushed in a different context.
var g = newGlobal('new-compartment');
g.eval('function f(a) {\n' +
' if (a == 1)\n' +
' debugger;\n' +
' else\n' +
' evaluate("f(" + a + " - 1);", {newContext: true});\n' +
'}\n');
var N = 9;
var dbg = new Debugger(g);
var frames = [];
var hits = 0;
dbg.onEnterFrame = function (frame) {
if (frame.type == "call" && frame.callee.name == "f") {
frames.push(frame);
frame.onPop = function () { assertEq(frames.pop(), frame); };
}
};
dbg.onDebuggerStatement = function (frame) {
assertEq(frames.length, N);
var i = N;
for (var f of frames)
assertEq(f.eval('a').return, i--);
hits++;
};
g.f(N);
assertEq(hits, 1);
assertEq(frames.length, 0);

View File

@ -822,7 +822,8 @@ ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thi
MaybeExtend extend;
if (evalInFrame) {
/* Though the prev-frame is given, need to search for prev-call. */
StackIter iter(cx, StackIter::GO_THROUGH_SAVED);
StackSegment &seg = cx->stack.space().containingSegment(evalInFrame);
StackIter iter(cx->runtime, seg);
while (!iter.isScript() || iter.fp() != evalInFrame)
++iter;
evalInFrameCalls = iter.calls_;
@ -1167,8 +1168,8 @@ StackIter::settleOnNewState()
if (op == JSOP_CALL || op == JSOP_FUNCALL) {
unsigned argc = GET_ARGC(pc_);
DebugOnly<unsigned> spoff = sp_ - fp_->base();
JS_ASSERT_IF(cx_->stackIterAssertionEnabled,
spoff == js_ReconstructStackDepth(cx_, fp_->script(), pc_));
JS_ASSERT_IF(maybecx_ && maybecx_->stackIterAssertionEnabled,
spoff == js_ReconstructStackDepth(maybecx_, fp_->script(), pc_));
Value *vp = sp_ - (2 + argc);
CrashIfInvalidSlot(fp_, vp);
@ -1217,7 +1218,7 @@ StackIter::settleOnNewState()
}
StackIter::StackIter(JSContext *cx, SavedOption savedOption)
: cx_(cx),
: maybecx_(cx),
savedOption_(savedOption)
{
#ifdef JS_METHODJIT
@ -1234,6 +1235,18 @@ StackIter::StackIter(JSContext *cx, SavedOption savedOption)
}
}
StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
: maybecx_(NULL), savedOption_(STOP_AT_SAVED)
{
#ifdef JS_METHODJIT
CompartmentVector &v = rt->compartments;
for (size_t i = 0; i < v.length(); i++)
mjit::ExpandInlineFrames(v[i]);
#endif
startOnSegment(&seg);
settleOnNewState();
}
StackIter &
StackIter::operator++()
{

View File

@ -1819,7 +1819,7 @@ class GeneratorFrameGuard : public FrameGuard
class StackIter
{
friend class ContextStack;
JSContext *cx_;
JSContext *maybecx_;
public:
enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
private:
@ -1846,6 +1846,7 @@ class StackIter
public:
StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
StackIter(JSRuntime *rt, StackSegment &seg);
bool done() const { return state_ == DONE; }
StackIter &operator++();