diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 1970a28aa1bb..938782f5c644 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1701,6 +1701,9 @@ CopyFromRematerializedFrame(JSContext* cx, JitActivation* act, uint8_t* fp, size for (size_t i = 0; i < frame->script()->nfixed(); i++) *frame->valueSlot(i) = rematFrame->locals()[i]; + if (rematFrame->hasCachedSavedFrame()) + frame->setHasCachedSavedFrame(); + JitSpew(JitSpew_BaselineBailouts, " Copied from rematerialized frame at (%p,%u)", fp, inlineDepth); diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index 50c0146a9b68..f986eaea34be 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -77,7 +77,12 @@ class BaselineFrame // If set, we're handling an exception for this frame. This is set for // debug mode OSR sanity checking when it handles corner cases which // only arise during exception handling. - HANDLING_EXCEPTION = 1 << 12 + HANDLING_EXCEPTION = 1 << 12, + + // If set, this frame has been on the stack when + // |js::SavedStacks::saveCurrentStack| was called, and so there is a + // |js::SavedFrame| object cached for this frame. + HAS_CACHED_SAVED_FRAME = 1 << 13 }; protected: // Silence Clang warning about unused private fields. @@ -323,6 +328,13 @@ class BaselineFrame flags_ &= ~HANDLING_EXCEPTION; } + bool hasCachedSavedFrame() const { + return flags_ & HAS_CACHED_SAVED_FRAME; + } + void setHasCachedSavedFrame() { + flags_ |= HAS_CACHED_SAVED_FRAME; + } + JSScript* evalScript() const { MOZ_ASSERT(isEvalFrame()); return evalScript_; diff --git a/js/src/jit/JitFrames.h b/js/src/jit/JitFrames.h index b091be912de0..4b4d85cc4f88 100644 --- a/js/src/jit/JitFrames.h +++ b/js/src/jit/JitFrames.h @@ -181,9 +181,10 @@ class OsiIndex // .. locals .. // The descriptor is organized into three sections: -// [ frame size | constructing bit | frame type ] +// [ frame size | has cached saved frame bit | frame type ] // < highest - - - - - - - - - - - - - - lowest > -static const uintptr_t FRAMESIZE_SHIFT = 4; +static const uintptr_t FRAMESIZE_SHIFT = 5; +static const uintptr_t HASCACHEDSAVEDFRAME_BIT = 1 << 4; static const uintptr_t FRAMETYPE_BITS = 4; // Ion frames have a few important numbers associated with them: @@ -282,7 +283,7 @@ void UpdateJitActivationsForMinorGC(JSRuntime* rt, JSTracer* trc); static inline uint32_t MakeFrameDescriptor(uint32_t frameSize, FrameType type) { - return (frameSize << FRAMESIZE_SHIFT) | type; + return 0 | (frameSize << FRAMESIZE_SHIFT) | type; } // Returns the JSScript associated with the topmost JIT frame. @@ -343,7 +344,13 @@ class CommonFrameLayout return descriptor_ >> FRAMESIZE_SHIFT; } void setFrameDescriptor(size_t size, FrameType type) { - descriptor_ = (size << FRAMESIZE_SHIFT) | type; + descriptor_ = 0 | (size << FRAMESIZE_SHIFT) | type; + } + bool hasCachedSavedFrame() const { + return descriptor_ & HASCACHEDSAVEDFRAME_BIT; + } + void setHasCachedSavedFrame() { + descriptor_ |= HASCACHEDSAVEDFRAME_BIT; } uint8_t* returnAddress() const { return returnAddress_; diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp index a7a463ab8155..4e020071f9ce 100644 --- a/js/src/jit/RematerializedFrame.cpp +++ b/js/src/jit/RematerializedFrame.cpp @@ -36,6 +36,7 @@ RematerializedFrame::RematerializedFrame(JSContext* cx, uint8_t* top, unsigned n : prevUpToDate_(false), isDebuggee_(iter.script()->isDebuggee()), isConstructing_(iter.isConstructing()), + hasCachedSavedFrame_(false), top_(top), pc_(iter.pc()), frameNo_(iter.frameNo()), diff --git a/js/src/jit/RematerializedFrame.h b/js/src/jit/RematerializedFrame.h index d1b9c9bbf462..27bc8c81ba36 100644 --- a/js/src/jit/RematerializedFrame.h +++ b/js/src/jit/RematerializedFrame.h @@ -35,6 +35,11 @@ class RematerializedFrame // Is this frame constructing? bool isConstructing_; + // If true, this frame has been on the stack when + // |js::SavedStacks::saveCurrentStack| was called, and so there is a + // |js::SavedFrame| object cached for this frame. + bool hasCachedSavedFrame_; + // The fp of the top frame associated with this possibly inlined frame. uint8_t* top_; @@ -169,6 +174,14 @@ class RematerializedFrame return isConstructing_; } + bool hasCachedSavedFrame() const { + return hasCachedSavedFrame_; + } + + void setHasCachedSavedFrame() { + hasCachedSavedFrame_ = true; + } + unsigned numFormalArgs() const { return maybeFun() ? fun()->nargs() : 0; } diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 93691f519979..e72a1c61b853 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -606,6 +606,27 @@ AbstractFramePtr::isDebuggerEvalFrame() const return false; } +inline bool +AbstractFramePtr::hasCachedSavedFrame() const +{ + if (isInterpreterFrame()) + return asInterpreterFrame()->hasCachedSavedFrame(); + if (isBaselineFrame()) + return asBaselineFrame()->hasCachedSavedFrame(); + return asRematerializedFrame()->hasCachedSavedFrame(); +} + +inline void +AbstractFramePtr::setHasCachedSavedFrame() +{ + if (isInterpreterFrame()) + asInterpreterFrame()->setHasCachedSavedFrame(); + else if (isBaselineFrame()) + asBaselineFrame()->setHasCachedSavedFrame(); + else + asRematerializedFrame()->setHasCachedSavedFrame(); +} + inline bool AbstractFramePtr::isDebuggee() const { diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 334a7ec67521..fc78c2f331da 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -471,6 +471,15 @@ InterpreterStack::pushExecuteFrame(JSContext* cx, HandleScript script, const Val /*****************************************************************************/ +bool +FrameIter::hasCachedSavedFrame(JSContext* cx, bool* hasCachedSavedFramep) +{ + if (isIon() && !ensureHasRematerializedFrame(cx)) + return false; + *hasCachedSavedFramep = abstractFramePtr().hasCachedSavedFrame(); + return true; +} + void FrameIter::popActivation() { diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 17f1e3d2c24c..ead9042efb25 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -196,6 +196,8 @@ class AbstractFramePtr inline bool isGlobalFrame() const; inline bool isEvalFrame() const; inline bool isDebuggerEvalFrame() const; + inline bool hasCachedSavedFrame() const; + inline void setHasCachedSavedFrame(); inline JSScript* script() const; inline JSFunction* fun() const; @@ -328,14 +330,22 @@ class InterpreterFrame /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */ HAS_PUSHED_SPS_FRAME = 0x10000, /* SPS was notified of enty */ + /* * If set, we entered one of the JITs and ScriptFrameIter should skip * this frame. */ - RUNNING_IN_JIT = 0x20000, + RUNNING_IN_JIT = 0x20000, /* Miscellaneous state. */ - CREATE_SINGLETON = 0x40000 /* Constructed |this| object should be singleton. */ + CREATE_SINGLETON = 0x40000, /* Constructed |this| object should be singleton. */ + + /* + * If set, this frame has been on the stack when + * |js::SavedStacks::saveCurrentStack| was called, and so there is a + * |js::SavedFrame| object cached for this frame. + */ + HAS_CACHED_SAVED_FRAME = 0x80000, }; private: @@ -898,6 +908,13 @@ class InterpreterFrame inline void unsetIsDebuggee(); + bool hasCachedSavedFrame() const { + return flags_ & HAS_CACHED_SAVED_FRAME; + } + void setHasCachedSavedFrame() { + flags_ |= HAS_CACHED_SAVED_FRAME; + } + public: void mark(JSTracer* trc); void markValues(JSTracer* trc, unsigned start, unsigned end); @@ -1720,6 +1737,8 @@ class FrameIter bool isNonEvalFunctionFrame() const; bool hasArgs() const { return isNonEvalFunctionFrame(); } + bool hasCachedSavedFrame(JSContext* cx, bool* hasCachedSavedFramep); + ScriptSource* scriptSource() const; const char* scriptFilename() const; const char16_t* scriptDisplayURL() const;