зеркало из 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
|
||||
StackIter::settleOnNewState()
|
||||
{
|
||||
|
@ -1119,7 +1140,8 @@ StackIter::settleOnNewState()
|
|||
bool containsFrame = seg_->contains(fp_);
|
||||
bool containsCall = seg_->contains(calls_);
|
||||
while (!containsFrame && !containsCall) {
|
||||
seg_ = seg_->prevInContext();
|
||||
/* Eval-in-frame can cross contexts, so use prevInMemory. */
|
||||
seg_ = seg_->prevInMemory();
|
||||
containsFrame = seg_->contains(fp_);
|
||||
containsCall = seg_->contains(calls_);
|
||||
|
||||
|
@ -1134,8 +1156,10 @@ StackIter::settleOnNewState()
|
|||
*this = tmp;
|
||||
return;
|
||||
}
|
||||
|
||||
/* There is no eval-in-frame equivalent for native calls. */
|
||||
JS_ASSERT_IF(containsCall, &seg_->calls() == calls_);
|
||||
|
||||
settleOnNewSegment();
|
||||
}
|
||||
|
||||
|
|
|
@ -140,11 +140,15 @@ namespace detail {
|
|||
*
|
||||
* An additional feature (perhaps not for much longer: bug 650361) is that
|
||||
* multiple independent "contexts" can interleave (LIFO) on a single contiguous
|
||||
* stack. "Independent" here means that neither context sees the other's
|
||||
* frames. 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
|
||||
* stack. "Independent" here means that each context has its own callstack.
|
||||
* Note, though, that eval-in-frame allows one context's callstack to join
|
||||
* another context's callstack. Thus, in general, the structure of calls in a
|
||||
* StackSpace is a forest.
|
||||
*
|
||||
* 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
|
||||
* perspective of cx1 and cx2. Thus, each segment has two links: prevInMemory
|
||||
* 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
|
||||
* callstack can either be the execution of a script (scripted function call,
|
||||
* global code, eval code, debugger code) or the invocation of a (C++) native.
|
||||
* Example usage:
|
||||
* Iterate through the callstack (following fp->prev) of the given context.
|
||||
* Each element of said callstack can either be the execution of a script
|
||||
* (scripted function call, global code, eval code, debugger code) or the
|
||||
* invocation of a (C++) native. Example usage:
|
||||
*
|
||||
* for (Stackiter i(cx); !i.done(); ++i) {
|
||||
* if (i.isScript()) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче