зеркало из https://github.com/mozilla/gecko-dev.git
Bug 758617 - Fix StackIter::settleOnNewState to handle cross-context eval-in-frame (r=jorendorff)
This commit is contained in:
Родитель
30f69421cd
Коммит
a28268350f
|
@ -0,0 +1,14 @@
|
||||||
|
var g = newGlobal('new-compartment');
|
||||||
|
g.eval('function f() { debugger; evaluate("debugger;", {newContext: true}); }');
|
||||||
|
|
||||||
|
var dbg = new Debugger(g);
|
||||||
|
var hits = 0;
|
||||||
|
dbg.onDebuggerStatement = function (frame1) {
|
||||||
|
dbg.onDebuggerStatement = function (frame2) {
|
||||||
|
assertEq(frame1.eval("throw 'ponies'").throw, 'ponies');
|
||||||
|
hits++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
g.f();
|
||||||
|
assertEq(hits, 1);
|
|
@ -1098,6 +1098,27 @@ CrashIfInvalidSlot(StackFrame *fp, Value *vp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given that the iterator's current value of fp_ and calls_ (initialized on
|
||||||
|
* construction or after operator++ popped the previous scripted/native call),
|
||||||
|
* "settle" the iterator on a new StackIter::State value. The goal is to
|
||||||
|
* present the client a simple linear sequence of native/scripted calls while
|
||||||
|
* covering up unpleasant stack implementation details:
|
||||||
|
* - The frame change can be "saved" and "restored" (see JS_SaveFrameChain).
|
||||||
|
* This artificially cuts the call chain and the StackIter client may want
|
||||||
|
* to continue through this cut to the previous frame by passing
|
||||||
|
* GO_THROUGH_SAVED.
|
||||||
|
* - fp->prev can be in a different contiguous segment from fp. In this case,
|
||||||
|
* the current values of sp/pc after calling popFrame/popCall are incorrect
|
||||||
|
* and should be recovered from fp->prev's segment.
|
||||||
|
* - there is no explicit relationship to determine whether fp_ or calls_ is
|
||||||
|
* the innermost invocation so implicit memory ordering is used since both
|
||||||
|
* push values on the stack.
|
||||||
|
* - calls to natives directly from JS do not push a record and thus the
|
||||||
|
* native call must be recovered by sniffing the stack.
|
||||||
|
* - a native call's 'callee' argument is clobbered on return while the
|
||||||
|
* CallArgsList element is still visible.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
StackIter::settleOnNewState()
|
StackIter::settleOnNewState()
|
||||||
{
|
{
|
||||||
|
@ -1119,7 +1140,8 @@ StackIter::settleOnNewState()
|
||||||
bool containsFrame = seg_->contains(fp_);
|
bool containsFrame = seg_->contains(fp_);
|
||||||
bool containsCall = seg_->contains(calls_);
|
bool containsCall = seg_->contains(calls_);
|
||||||
while (!containsFrame && !containsCall) {
|
while (!containsFrame && !containsCall) {
|
||||||
seg_ = seg_->prevInContext();
|
/* Eval-in-frame can cross contexts, so use prevInMemory. */
|
||||||
|
seg_ = seg_->prevInMemory();
|
||||||
containsFrame = seg_->contains(fp_);
|
containsFrame = seg_->contains(fp_);
|
||||||
containsCall = seg_->contains(calls_);
|
containsCall = seg_->contains(calls_);
|
||||||
|
|
||||||
|
@ -1134,8 +1156,10 @@ StackIter::settleOnNewState()
|
||||||
*this = tmp;
|
*this = tmp;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There is no eval-in-frame equivalent for native calls. */
|
/* There is no eval-in-frame equivalent for native calls. */
|
||||||
JS_ASSERT_IF(containsCall, &seg_->calls() == calls_);
|
JS_ASSERT_IF(containsCall, &seg_->calls() == calls_);
|
||||||
|
|
||||||
settleOnNewSegment();
|
settleOnNewSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,11 +140,15 @@ namespace detail {
|
||||||
*
|
*
|
||||||
* An additional feature (perhaps not for much longer: bug 650361) is that
|
* An additional feature (perhaps not for much longer: bug 650361) is that
|
||||||
* multiple independent "contexts" can interleave (LIFO) on a single contiguous
|
* multiple independent "contexts" can interleave (LIFO) on a single contiguous
|
||||||
* stack. "Independent" here means that neither context sees the other's
|
* stack. "Independent" here means that each context has its own callstack.
|
||||||
* frames. Concretely, an embedding may enter the JS engine on cx1 and then,
|
* Note, though, that eval-in-frame allows one context's callstack to join
|
||||||
* from a native called by the JS engine, reenter the VM on cx2. Changing from
|
* another context's callstack. Thus, in general, the structure of calls in a
|
||||||
* cx1 to cx2 causes a new segment to be started for cx2's stack on top of
|
* StackSpace is a forest.
|
||||||
* cx1's current segment. These two segments are linked from the perspective of
|
*
|
||||||
|
* More concretely, an embedding may enter the JS engine on cx1 and then, from
|
||||||
|
* a native called by the JS engine, reenter the VM on cx2. Changing from cx1
|
||||||
|
* to cx2 causes a new segment to be started for cx2's stack on top of cx1's
|
||||||
|
* current segment. These two segments are linked from the perspective of
|
||||||
* StackSpace, since they are adjacent on the thread's stack, but not from the
|
* StackSpace, since they are adjacent on the thread's stack, but not from the
|
||||||
* perspective of cx1 and cx2. Thus, each segment has two links: prevInMemory
|
* perspective of cx1 and cx2. Thus, each segment has two links: prevInMemory
|
||||||
* and prevInContext. Each independent stack is encapsulated and managed by
|
* and prevInContext. Each independent stack is encapsulated and managed by
|
||||||
|
@ -1773,10 +1777,10 @@ class GeneratorFrameGuard : public FrameGuard
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate through the callstack of the given context. Each element of said
|
* Iterate through the callstack (following fp->prev) of the given context.
|
||||||
* callstack can either be the execution of a script (scripted function call,
|
* Each element of said callstack can either be the execution of a script
|
||||||
* global code, eval code, debugger code) or the invocation of a (C++) native.
|
* (scripted function call, global code, eval code, debugger code) or the
|
||||||
* Example usage:
|
* invocation of a (C++) native. Example usage:
|
||||||
*
|
*
|
||||||
* for (Stackiter i(cx); !i.done(); ++i) {
|
* for (Stackiter i(cx); !i.done(); ++i) {
|
||||||
* if (i.isScript()) {
|
* if (i.isScript()) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче