From 3623056142c9c2637d870606b9b4222ca3842f86 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 12 Jan 2013 14:26:52 +0100 Subject: [PATCH] Bug 829579 - Rewrite AllFramesIter to iterate Ion frames too. r=luke --HG-- extra : rebase_source : 73b9cf6d2ab9b1a167cc6847fcc114045f796fc5 --- js/src/jscompartment.cpp | 2 +- js/src/jsscript.cpp | 2 +- js/src/vm/Debugger.cpp | 2 +- js/src/vm/ScopeObject.cpp | 2 +- js/src/vm/Stack.cpp | 94 +++++++++++++++++++++++++++++++++++---- js/src/vm/Stack.h | 25 ++++++++--- 6 files changed, 108 insertions(+), 19 deletions(-) diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index d76cd55b8d1..989a122b064 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -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()) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 091e86bafcf..10581b9d26f 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -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 diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index b30d5e9f76d..de2f93d24bc 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -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. diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 36b3168f41a..d9eb1ffab73 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -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. diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 0c1f9205efc..4ae1f8ca532 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -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(); } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 15f76415848..3f33249542a 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -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 */