Bug 829579 - Rewrite AllFramesIter to iterate Ion frames too. r=luke

--HG--
extra : rebase_source : 73b9cf6d2ab9b1a167cc6847fcc114045f796fc5
This commit is contained in:
Jan de Mooij 2013-01-12 14:26:52 +01:00
parent 3f4c90b945
commit 3623056142
6 changed files with 108 additions and 19 deletions

View File

@ -801,7 +801,7 @@ JSCompartment::onTooMuchMalloc()
bool
JSCompartment::hasScriptsOnStack()
{
for (AllFramesIter afi(rt->stackSpace); !afi.done(); ++afi) {
for (AllFramesIter afi(rt); !afi.done(); ++afi) {
#ifdef JS_ION
// If this is an Ion frame, check the IonActivation instead
if (afi.isIon())

View File

@ -2702,7 +2702,7 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
* assumption of !script->needsArgsObj();
* - type inference data for the script assuming script->needsArgsObj; and
*/
for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) {
for (AllFramesIter i(cx->runtime); !i.done(); ++i) {
/*
* We cannot reliably create an arguments object for Ion activations of
* this script. To maintain the invariant that "script->needsArgsObj

View File

@ -1984,7 +1984,7 @@ Debugger::getNewestFrame(JSContext *cx, unsigned argc, Value *vp)
* cx->fp() would return the topmost frame in the current context.
* Since there may be multiple contexts, use AllFramesIter instead.
*/
for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) {
for (AllFramesIter i(cx->runtime); !i.done(); ++i) {
/*
* Debug-mode currently disables Ion compilation in the compartment of
* the debuggee.

View File

@ -1922,7 +1922,7 @@ DebugScopes::updateLiveScopes(JSContext *cx)
* to date' bit for fp->prev() in fp, simply popping fp effectively clears
* the flag for us, at exactly the time when execution resumes fp->prev().
*/
for (AllFramesIter i(cx->runtime->stackSpace); !i.done(); ++i) {
for (AllFramesIter i(cx->runtime); !i.done(); ++i) {
/*
* Debug-mode currently disables Ion compilation in the compartment of
* the debuggee.

View File

@ -816,7 +816,9 @@ StackSpace::sizeOf()
bool
StackSpace::containsSlow(StackFrame *fp)
{
for (AllFramesIter i(*this); !i.done(); ++i) {
if (!seg_)
return false;
for (AllFramesIter i(seg_->cx()->runtime); !i.done(); ++i) {
/*
* Debug-mode currently disables Ion compilation in the compartment of
* the debuggee.
@ -2041,24 +2043,75 @@ StackIter::frameSlotValue(size_t index) const
/*****************************************************************************/
AllFramesIter::AllFramesIter(StackSpace &space)
: seg_(space.seg_),
AllFramesIter::AllFramesIter(JSRuntime *rt)
: seg_(rt->stackSpace.seg_),
fp_(seg_ ? seg_->maybefp() : NULL)
#ifdef JS_ION
, ionActivations_(rt),
ionFrames_((uint8_t *)NULL)
#endif
{
settle();
settleOnNewState();
}
#ifdef JS_ION
void
AllFramesIter::popIonFrame()
{
JS_ASSERT(state_ == ION);
++ionFrames_;
while (!ionFrames_.done() && !ionFrames_.isScripted())
++ionFrames_;
if (!ionFrames_.done())
return;
// The activation has no other frames. If entryfp is NULL, it was invoked
// by a native written in C++, using FastInvoke, on top of another activation.
ion::IonActivation *activation = ionActivations_.activation();
if (!activation->entryfp()) {
JS_ASSERT(activation->prevpc());
JS_ASSERT(fp_->beginsIonActivation());
++ionActivations_;
settleOnNewState();
return;
}
if (fp_->runningInIon()) {
++ionActivations_;
fp_ = fp_->prev();
settleOnNewState();
} else {
JS_ASSERT(fp_->callingIntoIon());
state_ = SCRIPTED;
++ionActivations_;
}
}
#endif
AllFramesIter&
AllFramesIter::operator++()
{
JS_ASSERT(!done());
fp_ = fp_->prev();
settle();
switch (state_) {
case SCRIPTED:
fp_ = fp_->prev();
settleOnNewState();
break;
#ifdef JS_ION
case ION:
popIonFrame();
break;
#endif
case DONE:
default:
JS_NOT_REACHED("Unexpeced state");
}
return *this;
}
void
AllFramesIter::settle()
AllFramesIter::settleOnNewState()
{
while (seg_ && (!fp_ || !seg_->contains(fp_))) {
seg_ = seg_->prevInMemory();
@ -2067,10 +2120,33 @@ AllFramesIter::settle()
JS_ASSERT(!!seg_ == !!fp_);
JS_ASSERT_IF(fp_, seg_->contains(fp_));
#ifdef JS_ION
if (fp_ && fp_->beginsIonActivation()) {
// Start at the first scripted frame.
ionFrames_ = ion::IonFrameIterator(ionActivations_);
while (!ionFrames_.isScripted() && !ionFrames_.done())
++ionFrames_;
state_ = ionFrames_.done() ? SCRIPTED : ION;
return;
}
#endif
state_ = fp_ ? SCRIPTED : DONE;
}
TaggedFramePtr
AllFramesIter::taggedFramePtr() const
{
return TaggedFramePtr(interpFrame());
switch (state_) {
case SCRIPTED:
return TaggedFramePtr(interpFrame());
case ION:
break;
case DONE:
break;
}
JS_NOT_REACHED("Unexpected state");
return TaggedFramePtr();
}

View File

@ -2159,26 +2159,39 @@ class NonBuiltinScriptFrameIter : public StackIter
/*
* Blindly iterate over all frames in the current thread's stack. These frames
* can be from different contexts and compartments, so beware.
* can be from different contexts and compartments, so beware. Iterates over
* Ion frames, but does not handle inlined frames.
*/
class AllFramesIter
{
public:
AllFramesIter(StackSpace &space);
AllFramesIter(JSRuntime *rt);
bool done() const { return fp_ == NULL; }
bool done() const { return state_ == DONE; }
AllFramesIter& operator++();
bool isIon() const { return fp_->runningInIon(); }
StackFrame *interpFrame() const { return fp_; }
bool isIon() const { return state_ == ION; }
StackFrame *interpFrame() const { JS_ASSERT(state_ == SCRIPTED); return fp_; }
StackSegment *seg() const { return seg_; }
TaggedFramePtr taggedFramePtr() const;
private:
void settle();
enum State { DONE, SCRIPTED, ION };
#ifdef JS_ION
void popIonFrame();
#endif
void settleOnNewState();
StackSegment *seg_;
StackFrame *fp_;
State state_;
#ifdef JS_ION
ion::IonActivationIterator ionActivations_;
ion::IonFrameIterator ionFrames_;
#endif
};
} /* namespace js */