author | Wes Kocher <wkocher@mozilla.com> |
Mon, 13 Oct 2014 09:31:11 -0700 | |
changeset 210187 | 4c4092b50ccb733a946076ad344a449b8e816205 |
parent 210186 | e00ce29c8c6716436164bb0fa66fbb641aa21e80 |
child 210188 | d29a91fd9c40ad85d921e2aa76c29f8bf8f7f1c6 |
push id | 1 |
push user | root |
push date | Mon, 20 Oct 2014 17:29:22 +0000 |
bugs | 1070962 |
milestone | 35.0a1 |
backs out | e00ce29c8c6716436164bb0fa66fbb641aa21e80 8876a417bd4f0f0045a1bf1a726640b87bc5630f 191e57386752fcf7a849b26a8d980212d8656297 3aac2b77e38f6abe9a5a05001560accd4de08ae7 d4dd598af9ac9615013e9cfecad99e72ae7bc6e0 4b8b34a91096b9048b7dfd27eb16ff6be07b32fa |
--- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -19,42 +19,89 @@ #include "vm/Probes-inl.h" #include "vm/Stack-inl.h" using namespace js; using namespace js::jit; using mozilla::IsInRange; +// These constructor are exactly the same except for the type of the iterator +// which is given to the SnapshotIterator constructor. Doing so avoid the +// creation of virtual functions for the IonIterator but may introduce some +// weirdness as IonInlineIterator is using a JitFrameIterator reference. +// +// If a function relies on ionScript() or to use OsiIndex(), due to the +// lack of virtual, these functions will use the JitFrameIterator reference +// contained in the InlineFrameIterator and thus are not able to recover +// correctly the data stored in IonBailoutIterator. +// +// Currently, such cases should not happen because our only use case of the +// JitFrameIterator within InlineFrameIterator is to read the frame content, or +// to clone it to find the parent scripted frame. Both use cases are fine and +// should not cause any issue since the only potential issue is to read the +// bailed out frame. + +SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter) + : snapshot_(iter.ionScript()->snapshots(), + iter.snapshotOffset(), + iter.ionScript()->snapshotsRVATableSize(), + iter.ionScript()->snapshotsListSize()), + recover_(snapshot_, + iter.ionScript()->recovers(), + iter.ionScript()->recoversSize()), + fp_(iter.jsFrame()), + machine_(iter.machineState()), + ionScript_(iter.ionScript()), + instructionResults_(nullptr) +{ +} + +void +IonBailoutIterator::dump() const +{ + if (type_ == JitFrame_IonJS) { + InlineFrameIterator frames(GetJSContextFromJitCode(), this); + for (;;) { + frames.dump(); + if (!frames.more()) + break; + ++frames; + } + } else { + JitFrameIterator::dump(); + } +} + uint32_t jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo) { JSContext *cx = GetJSContextFromJitCode(); MOZ_ASSERT(bailoutInfo); // We don't have an exit frame. MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) && IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000), "Fake jitTop pointer should be within the first page."); cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT; gc::AutoSuppressGC suppress(cx); JitActivationIterator jitActivations(cx->runtime()); - BailoutFrameInfo bailoutData(jitActivations, sp); - JitFrameIterator iter(jitActivations); + IonBailoutIterator iter(jitActivations, sp); + JitActivation *activation = jitActivations->asJit(); TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); TraceLogTimestamp(logger, TraceLogger::Bailout); JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset()); MOZ_ASSERT(IsBaselineEnabled(cx)); *bailoutInfo = nullptr; - uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo); + uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo); MOZ_ASSERT(retval == BAILOUT_RETURN_OK || retval == BAILOUT_RETURN_FATAL_ERROR || retval == BAILOUT_RETURN_OVERRECURSED); MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr); if (retval != BAILOUT_RETURN_OK) { // If the bailout failed, then bailout trampoline will pop the // current frame and jump straight to exception handling code when @@ -86,31 +133,31 @@ jit::InvalidationBailout(InvalidationBai JSContext *cx = GetJSContextFromJitCode(); // We don't have an exit frame. cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT; gc::AutoSuppressGC suppress(cx); JitActivationIterator jitActivations(cx->runtime()); - BailoutFrameInfo bailoutData(jitActivations, sp); - JitFrameIterator iter(jitActivations); + IonBailoutIterator iter(jitActivations, sp); + JitActivation *activation = jitActivations->asJit(); TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); TraceLogTimestamp(logger, TraceLogger::Invalidation); JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset()); // Note: the frame size must be computed before we return from this function. - *frameSizeOut = iter.frameSize(); + *frameSizeOut = iter.topFrameSize(); MOZ_ASSERT(IsBaselineEnabled(cx)); *bailoutInfo = nullptr; - uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo); + uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo); MOZ_ASSERT(retval == BAILOUT_RETURN_OK || retval == BAILOUT_RETURN_FATAL_ERROR || retval == BAILOUT_RETURN_OVERRECURSED); MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr); if (retval != BAILOUT_RETURN_OK) { // If the bailout failed, then bailout trampoline will pop the // current frame and jump straight to exception handling code when @@ -143,26 +190,29 @@ jit::InvalidationBailout(InvalidationBai JitSpew(JitSpew_IonInvalidate, " new ra %p", (void *) frame->returnAddress()); } iter.ionScript()->decref(cx->runtime()->defaultFreeOp()); return retval; } -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - const JitFrameIterator &frame) - : machine_(frame.machineState()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + const JitFrameIterator &frame) + : JitFrameIterator(activations), + machine_(frame.machineState()) { - framePointer_ = (uint8_t *) frame.fp(); - topFrameSize_ = frame.frameSize(); + kind_ = Kind_BailoutIterator; + returnAddressToFp_ = frame.returnAddressToFp(); topIonScript_ = frame.ionScript(); - attachOnJitActivation(activations); + const OsiIndex *osiIndex = frame.osiIndex(); - const OsiIndex *osiIndex = frame.osiIndex(); + current_ = (uint8_t *) frame.fp(); + type_ = JitFrame_IonJS; + topFrameSize_ = frame.frameSize(); snapshotOffset_ = osiIndex->snapshotOffset(); } uint32_t jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe, const ExceptionBailoutInfo &excInfo, bool *overrecursed) @@ -171,21 +221,21 @@ jit::ExceptionHandlerBailout(JSContext * // actual exception pending. For instance, when we return false from an // operation callback like a timeout handler. MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending()); cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT; gc::AutoSuppressGC suppress(cx); JitActivationIterator jitActivations(cx->runtime()); - BailoutFrameInfo bailoutData(jitActivations, frame.frame()); - JitFrameIterator iter(jitActivations); + IonBailoutIterator iter(jitActivations, frame.frame()); + JitActivation *activation = jitActivations->asJit(); BaselineBailoutInfo *bailoutInfo = nullptr; - uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo); + uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo); if (retval == BAILOUT_RETURN_OK) { MOZ_ASSERT(bailoutInfo); // Overwrite the kind so HandleException after the bailout returns // false, jumping directly to the exception tail. if (excInfo.propagatingIonExceptionForDebugMode()) bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode; @@ -242,21 +292,8 @@ jit::CheckFrequentBailouts(JSContext *cx if (!Invalidate(cx, script)) return false; } } return true; } - -void -BailoutFrameInfo::attachOnJitActivation(const JitActivationIterator &jitActivations) -{ - MOZ_ASSERT(jitActivations.jitTop() == FAKE_JIT_TOP_FOR_BAILOUT); - activation_ = jitActivations->asJit(); - activation_->setBailoutData(this); -} - -BailoutFrameInfo::~BailoutFrameInfo() -{ - activation_->cleanBailoutData(); -}
--- a/js/src/jit/Bailouts.h +++ b/js/src/jit/Bailouts.h @@ -108,54 +108,60 @@ class JitCompartment; // BailoutStack is an architecture specific pointer to the stack, given by the // bailout handler. class BailoutStack; class InvalidationBailoutStack; // Must be implemented by each architecture. -// This structure is constructed before recovering the baseline frames for a -// bailout. It records all information extracted from the stack, and which are -// needed for the JitFrameIterator. -class BailoutFrameInfo +// This iterator is constructed at a time where there is no exit frame at the +// moment. They must be initialized to the first JS frame instead of the exit +// frame as usually done with JitFrameIterator. +class IonBailoutIterator : public JitFrameIterator { MachineState machine_; - uint8_t *framePointer_; + uint32_t snapshotOffset_; size_t topFrameSize_; IonScript *topIonScript_; - uint32_t snapshotOffset_; - JitActivation *activation_; - - void attachOnJitActivation(const JitActivationIterator &activations); public: - BailoutFrameInfo(const JitActivationIterator &activations, BailoutStack *sp); - BailoutFrameInfo(const JitActivationIterator &activations, InvalidationBailoutStack *sp); - BailoutFrameInfo(const JitActivationIterator &activations, const JitFrameIterator &frame); - ~BailoutFrameInfo(); + IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp); + IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp); + IonBailoutIterator(const JitActivationIterator &activations, const JitFrameIterator &frame); - uint8_t *fp() const { - return framePointer_; - } SnapshotOffset snapshotOffset() const { - return snapshotOffset_; + if (topIonScript_) + return snapshotOffset_; + return osiIndex()->snapshotOffset(); } const MachineState machineState() const { - return machine_; + if (topIonScript_) + return machine_; + return JitFrameIterator::machineState(); } size_t topFrameSize() const { + MOZ_ASSERT(topIonScript_); return topFrameSize_; } IonScript *ionScript() const { - return topIonScript_; + if (topIonScript_) + return topIonScript_; + return JitFrameIterator::ionScript(); } - JitActivation *activation() const { - return activation_; + + IonBailoutIterator &operator++() { + JitFrameIterator::operator++(); + // Clear topIonScript_ now that we've advanced past it, so that + // snapshotOffset() and machineState() reflect the current script. + topIonScript_ = nullptr; + return *this; } + + void dump() const; }; bool EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp); struct BaselineBailoutInfo; // Called from a bailout thunk. Returns a BAILOUT_* error code. uint32_t Bailout(BailoutStack *sp, BaselineBailoutInfo **info);
--- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -69,42 +69,41 @@ class BufferPointer * needs to be enlarged to accomodate new data. Similarly to the C stack, the * data that's written to the reconstructed stack grows from high to low in memory. * * The lowest region of the allocated memory contains a BaselineBailoutInfo structure that * points to the start and end of the written data. */ struct BaselineStackBuilder { - JitFrameIterator &iter_; + IonBailoutIterator &iter_; IonJSFrameLayout *frame_; static size_t HeaderSize() { return AlignBytes(sizeof(BaselineBailoutInfo), sizeof(void *)); } size_t bufferTotal_; size_t bufferAvail_; size_t bufferUsed_; uint8_t *buffer_; BaselineBailoutInfo *header_; size_t framePushed_; - BaselineStackBuilder(JitFrameIterator &iter, size_t initialSize) + BaselineStackBuilder(IonBailoutIterator &iter, size_t initialSize) : iter_(iter), frame_(static_cast<IonJSFrameLayout*>(iter.current())), bufferTotal_(initialSize), bufferAvail_(0), bufferUsed_(0), buffer_(nullptr), header_(nullptr), framePushed_(0) { MOZ_ASSERT(bufferTotal_ >= HeaderSize()); - MOZ_ASSERT(iter.isBailoutJS()); } ~BaselineStackBuilder() { js_free(buffer_); } bool init() { MOZ_ASSERT(!buffer_); @@ -383,21 +382,20 @@ struct BaselineStackBuilder // Ensure that all value locations are readable from the SnapshotIterator. // Remove RInstructionResults from the JitActivation if the frame got recovered // ahead of the bailout. class SnapshotIteratorForBailout : public SnapshotIterator { RInstructionResults results_; public: - SnapshotIteratorForBailout(const JitFrameIterator &iter) + SnapshotIteratorForBailout(const IonBailoutIterator &iter) : SnapshotIterator(iter), results_(iter.jsFrame()) { - MOZ_ASSERT(iter.isBailoutJS()); } // Take previously computed result out of the activation, or compute the // results of all recover instructions contained in the snapshot. bool init(JSContext *cx, JitActivation *activation) { activation->maybeTakeIonFrameRecovery(fp_, &results_); if (!results_.isInitialized() && !computeInstructionResults(cx, &results_)) return false; @@ -1284,17 +1282,17 @@ InitFromBailout(JSContext *cx, HandleScr MOZ_ASSERT(rectReturnAddr); if (!builder.writePtr(rectReturnAddr, "ReturnAddr")) return false; return true; } uint32_t -jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter, +jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter, bool invalidate, BaselineBailoutInfo **bailoutInfo, const ExceptionBailoutInfo *excInfo) { // The Baseline frames we will reconstruct on the heap are not rooted, so GC // must be suppressed here. MOZ_ASSERT(cx->mainThread().suppressGC); MOZ_ASSERT(bailoutInfo != nullptr); @@ -1304,17 +1302,17 @@ jit::BailoutIonToBaseline(JSContext *cx, TraceLogStopEvent(logger, TraceLogger::IonMonkey); TraceLogStartEvent(logger, TraceLogger::Baseline); // The caller of the top frame must be one of the following: // IonJS - Ion calling into Ion. // BaselineStub - Baseline calling into Ion. // Entry - Interpreter or other calling into Ion. // Rectifier - Arguments rectifier calling into Ion. - MOZ_ASSERT(iter.isBailoutJS()); + MOZ_ASSERT(iter.isIonJS()); FrameType prevFrameType = iter.prevType(); MOZ_ASSERT(prevFrameType == JitFrame_IonJS || prevFrameType == JitFrame_BaselineStub || prevFrameType == JitFrame_Entry || prevFrameType == JitFrame_Rectifier); // All incoming frames are going to look like this: //
--- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -432,17 +432,17 @@ struct BaselineBailoutInfo // Number of baseline frames to push on the stack. uint32_t numFrames; // The bailout kind. BailoutKind bailoutKind; }; uint32_t -BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter, +BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter, bool invalidate, BaselineBailoutInfo **bailoutInfo, const ExceptionBailoutInfo *exceptionInfo = nullptr); // Mark baseline scripts on the stack as active, so that they are not discarded // during GC. void MarkActiveBaselineScripts(Zone *zone);
--- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -619,17 +619,17 @@ FinishAllOffThreadCompilations(JSCompart } uint8_t * jit::LazyLinkTopActivation(JSContext *cx) { JitActivationIterator iter(cx->runtime()); // First frame should be an exit frame. - JitFrameIterator it(iter); + JitFrameIterator it(iter.jitTop(), SequentialExecution); MOZ_ASSERT(it.type() == JitFrame_Exit); // Second frame is the Ion frame. ++it; MOZ_ASSERT(it.type() == JitFrame_IonJS); // Get the pending builder from the Ion frame. IonBuilder *builder = it.script()->ionScript()->pendingBuilder(); @@ -1879,17 +1879,17 @@ AttachFinishedCompilations(JSContext *cx #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) // Try to defer linking if the script is on the stack, to postpone // invalidating them. if (builder->info().executionMode() == SequentialExecution && builder->script()->hasIonScript()) { bool onStack = false; for (JitActivationIterator iter(cx->runtime()); !iter.done(); ++iter) { - for (JitFrameIterator it(iter); !it.done(); ++it) { + for (JitFrameIterator it(iter.jitTop(), SequentialExecution); !it.done(); ++it) { if (!it.isIonJS()) continue; if (it.checkInvalidation()) continue; JSScript *script = it.script(); if (builder->script() == script) { onStack = true; @@ -2681,42 +2681,35 @@ jit::FastInvoke(JSContext *cx, HandleFun args.rval().set(result); MOZ_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR)); return result.isMagic() ? IonExec_Error : IonExec_Ok; } static void -InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool invalidateAll) +InvalidateActivation(FreeOp *fop, uint8_t *jitTop, bool invalidateAll) { JitSpew(JitSpew_IonInvalidate, "BEGIN invalidating activation"); size_t frameno = 1; - for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) { + for (JitFrameIterator it(jitTop, SequentialExecution); !it.done(); ++it, ++frameno) { MOZ_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit); #ifdef DEBUG switch (it.type()) { case JitFrame_Exit: JitSpew(JitSpew_IonInvalidate, "#%d exit frame @ %p", frameno, it.fp()); break; case JitFrame_BaselineJS: case JitFrame_IonJS: - case JitFrame_Bailout: { MOZ_ASSERT(it.isScripted()); - const char *type = "Unknown"; - if (it.isIonJS()) - type = "Optimized"; - else if (it.isBaselineJS()) - type = "Baseline"; - else if (it.isBailoutJS()) - type = "Bailing"; + const char *type = it.isIonJS() ? "Optimized" : "Baseline"; JitSpew(JitSpew_IonInvalidate, "#%d %s JS frame @ %p, %s:%d (fun: %p, script: %p, pc %p)", frameno, type, it.fp(), it.script()->filename(), it.script()->lineno(), it.maybeCallee(), (JSScript *)it.script(), it.returnAddressToFp()); break; } case JitFrame_BaselineStub: JitSpew(JitSpew_IonInvalidate, "#%d baseline stub frame @ %p", frameno, it.fp()); break; @@ -2843,17 +2836,17 @@ void jit::InvalidateAll(FreeOp *fop, Zone *zone) { for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) StopAllOffThreadCompilations(comp); for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter) { if (iter->compartment()->zone() == zone) { JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC"); - InvalidateActivation(fop, iter, true); + InvalidateActivation(fop, iter.jitTop(), true); } } } void jit::Invalidate(types::TypeZone &types, FreeOp *fop, const Vector<types::RecompileInfo> &invalid, bool resetUses, @@ -2886,17 +2879,17 @@ jit::Invalidate(types::TypeZone &types, } if (!numInvalidations) { JitSpew(JitSpew_IonInvalidate, " No IonScript invalidation."); return; } for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter) - InvalidateActivation(fop, iter, false); + InvalidateActivation(fop, iter.jitTop(), false); // Drop the references added above. If a script was never active, its // IonScript will be immediately destroyed. Otherwise, it will be held live // until its last invalidated frame is destroyed. for (size_t i = 0; i < invalid.length(); i++) { types::CompilerOutput &co = *invalid[i].compilerOutput(types); if (!co.isValid()) continue; @@ -3352,17 +3345,17 @@ AutoDebugModeInvalidation::~AutoDebugMod // mode. jit::MarkActiveBaselineScripts(zone); for (JitActivationIterator iter(rt); !iter.done(); ++iter) { JSCompartment *comp = iter->compartment(); if (comp_ == comp || zone_ == comp->zone()) { IonContext ictx(CompileRuntime::get(rt)); JitSpew(JitSpew_IonInvalidate, "Invalidating frames for debug mode toggle"); - InvalidateActivation(fop, iter, true); + InvalidateActivation(fop, iter.jitTop(), true); } } for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->compartment() == comp_ || zone_) { FinishInvalidation<SequentialExecution>(fop, script); FinishInvalidation<ParallelExecution>(fop, script);
--- a/js/src/jit/IonFrames-inl.h +++ b/js/src/jit/IonFrames-inl.h @@ -75,12 +75,24 @@ GetTopBaselineFrame(JSContext *cx) MOZ_ASSERT(iter.type() == JitFrame_Exit); ++iter; if (iter.isBaselineStub()) ++iter; MOZ_ASSERT(iter.isBaselineJS()); return iter.baselineFrame(); } +inline JSScript * +GetTopIonJSScript(JSContext *cx, void **returnAddrOut = nullptr) +{ + return GetTopIonJSScript(cx->mainThread().jitTop, returnAddrOut, SequentialExecution); +} + +inline JSScript * +GetTopIonJSScript(ForkJoinContext *cx, void **returnAddrOut = nullptr) +{ + return GetTopIonJSScript(cx->perThreadData->jitTop, returnAddrOut, ParallelExecution); +} + } // namespace jit } // namespace js #endif /* jit_IonFrames_inl_h */
--- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -75,58 +75,63 @@ ReadFrameInt32Slot(IonJSFrameLayout *fp, } static inline bool ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot) { return *(bool *)((char *)fp + OffsetOfFrameSlot(slot)); } -JitFrameIterator::JitFrameIterator() - : current_(nullptr), - type_(JitFrame_Exit), - returnAddressToFp_(nullptr), - frameSize_(0), - mode_(SequentialExecution), - cachedSafepointIndex_(nullptr), - activation_(nullptr) -{ -} - JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx) : current_(cx->perThreadData->jitTop), type_(JitFrame_Exit), returnAddressToFp_(nullptr), frameSize_(0), mode_(cx->isForkJoinContext() ? ParallelExecution : SequentialExecution), + kind_(Kind_FrameIterator), cachedSafepointIndex_(nullptr), - activation_(cx->perThreadData->activation()->asJit()) + activation_(nullptr) { - if (activation_->bailoutData()) { - current_ = activation_->bailoutData()->fp(); - frameSize_ = activation_->bailoutData()->topFrameSize(); - type_ = JitFrame_Bailout; - } } JitFrameIterator::JitFrameIterator(const ActivationIterator &activations) : current_(activations.jitTop()), type_(JitFrame_Exit), returnAddressToFp_(nullptr), frameSize_(0), mode_(activations->asJit()->cx()->isForkJoinContext() ? ParallelExecution : SequentialExecution), + kind_(Kind_FrameIterator), cachedSafepointIndex_(nullptr), activation_(activations->asJit()) { - if (activation_->bailoutData()) { - current_ = activation_->bailoutData()->fp(); - frameSize_ = activation_->bailoutData()->topFrameSize(); - type_ = JitFrame_Bailout; - } +} + +JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode) + : current_((uint8_t *)fp), + type_(JitFrame_IonJS), + returnAddressToFp_(fp->returnAddress()), + frameSize_(fp->prevFrameLocalSize()), + mode_(mode), + kind_(Kind_FrameIterator) +{ +} + +IonBailoutIterator * +JitFrameIterator::asBailoutIterator() +{ + MOZ_ASSERT(isBailoutIterator()); + return static_cast<IonBailoutIterator *>(this); +} + +const IonBailoutIterator * +JitFrameIterator::asBailoutIterator() const +{ + MOZ_ASSERT(isBailoutIterator()); + return static_cast<const IonBailoutIterator *>(this); } bool JitFrameIterator::checkInvalidation() const { IonScript *dummy; return checkInvalidation(&dummy); } @@ -263,17 +268,16 @@ JitFrameIterator::actualArgs() const static inline size_t SizeOfFramePrefix(FrameType type) { switch (type) { case JitFrame_Entry: return IonEntryFrameLayout::Size(); case JitFrame_BaselineJS: case JitFrame_IonJS: - case JitFrame_Bailout: case JitFrame_Unwound_IonJS: return IonJSFrameLayout::Size(); case JitFrame_BaselineStub: return IonBaselineStubFrameLayout::Size(); case JitFrame_Rectifier: return IonRectifierFrameLayout::Size(); case JitFrame_Unwound_Rectifier: return IonUnwoundRectifierFrameLayout::Size(); @@ -328,34 +332,26 @@ JitFrameIterator::operator++() return *this; } uintptr_t * JitFrameIterator::spillBase() const { - MOZ_ASSERT(isIonJS()); - // Get the base address to where safepoint registers are spilled. // Out-of-line calls do not unwind the extra padding space used to // aggregate bailout tables, so we use frameSize instead of frameLocals, // which would only account for local stack slots. return reinterpret_cast<uintptr_t *>(fp() - ionScript()->frameSize()); } MachineState JitFrameIterator::machineState() const { - MOZ_ASSERT(isIonScripted()); - - // The MachineState is used by GCs for marking call-sites. - if (MOZ_UNLIKELY(isBailoutJS())) - return activation_->bailoutData()->machineState(); - SafepointReader reader(ionScript(), safepoint()); uintptr_t *spill = spillBase(); MachineState machine; for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++) machine.setRegisterLocation(*iter, --spill); uint8_t *spillAlign = alignDoubleSpillWithOffset(reinterpret_cast<uint8_t *>(spill), 0); @@ -1034,17 +1030,17 @@ MarkBaselineStubFrame(JSTracer *trc, con MOZ_ASSERT(ICStub::CanMakeCalls(stub->kind())); stub->trace(trc); } } void JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end) { - JitFrameIterator frames(*this); + JitFrameIterator frames(jitTop(), SequentialExecution); if (frames.isFakeExitFrame()) { min = reinterpret_cast<uintptr_t *>(frames.fp()); } else { IonExitFrameLayout *exitFrame = frames.exitFrame(); IonExitFooterFrame *footer = exitFrame->footer(); const VMFunction *f = footer->function(); if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) { @@ -1365,18 +1361,17 @@ void UpdateJitActivationsForMinorGC<gc:: void GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes) { JitSpew(JitSpew_IonSnapshots, "Recover PC & Script from the last frame."); JSRuntime *rt = cx->runtime(); // Recover the return address. - JitActivationIterator iter(rt); - JitFrameIterator it(iter); + JitFrameIterator it(rt->mainThread.jitTop, SequentialExecution); // If the previous frame is a rectifier frame (maybe unwound), // skip past it. if (it.prevType() == JitFrame_Rectifier || it.prevType() == JitFrame_Unwound_Rectifier) { ++it; MOZ_ASSERT(it.prevType() == JitFrame_BaselineStub || it.prevType() == JitFrame_BaselineJS || it.prevType() == JitFrame_IonJS); @@ -1529,17 +1524,17 @@ SnapshotIterator::SnapshotIterator(IonSc ionScript_(ionScript), instructionResults_(nullptr) { MOZ_ASSERT(snapshotOffset < ionScript->snapshotsListSize()); } SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter) : snapshot_(iter.ionScript()->snapshots(), - iter.snapshotOffset(), + iter.osiIndex()->snapshotOffset(), iter.ionScript()->snapshotsRVATableSize(), iter.ionScript()->snapshotsListSize()), recover_(snapshot_, iter.ionScript()->recovers(), iter.ionScript()->recoversSize()), fp_(iter.jsFrame()), machine_(iter.machineState()), ionScript_(iter.ionScript()), @@ -1913,77 +1908,54 @@ SnapshotIterator::maybeReadAllocByIndex( } while (moreAllocations()) skip(); return s; } -IonJSFrameLayout * -JitFrameIterator::jsFrame() const -{ - MOZ_ASSERT(isScripted()); - if (isBailoutJS()) - return (IonJSFrameLayout *) activation_->bailoutData()->fp(); - - return (IonJSFrameLayout *) fp(); -} - IonScript * JitFrameIterator::ionScript() const { - MOZ_ASSERT(isIonScripted()); - if (isBailoutJS()) - return activation_->bailoutData()->ionScript(); + MOZ_ASSERT(type() == JitFrame_IonJS); IonScript *ionScript = nullptr; if (checkInvalidation(&ionScript)) return ionScript; return ionScriptFromCalleeToken(); } IonScript * JitFrameIterator::ionScriptFromCalleeToken() const { - MOZ_ASSERT(isIonJS()); + MOZ_ASSERT(type() == JitFrame_IonJS); MOZ_ASSERT(!checkInvalidation()); switch (mode_) { case SequentialExecution: return script()->ionScript(); case ParallelExecution: return script()->parallelIonScript(); default: MOZ_CRASH("No such execution mode"); } } const SafepointIndex * JitFrameIterator::safepoint() const { - MOZ_ASSERT(isIonJS()); if (!cachedSafepointIndex_) cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp()); return cachedSafepointIndex_; } -SnapshotOffset -JitFrameIterator::snapshotOffset() const -{ - MOZ_ASSERT(isIonScripted()); - if (isBailoutJS()) - return activation_->bailoutData()->snapshotOffset(); - return osiIndex()->snapshotOffset(); -} - const OsiIndex * JitFrameIterator::osiIndex() const { - MOZ_ASSERT(isIonJS()); SafepointReader reader(ionScript(), safepoint()); return ionScript()->getOsiIndex(reader.osiReturnPointOffset()); } InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter) : callee_(cx), script_(cx) { @@ -1992,25 +1964,41 @@ InlineFrameIterator::InlineFrameIterator InlineFrameIterator::InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter) : callee_(rt), script_(rt) { resetOn(iter); } +InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter) + : frame_(iter), + framesRead_(0), + frameCount_(UINT32_MAX), + callee_(cx), + script_(cx) +{ + if (iter) { + start_ = SnapshotIterator(*iter); + findNextFrame(); + } +} + InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter) : frame_(iter ? iter->frame_ : nullptr), framesRead_(0), frameCount_(iter ? iter->frameCount_ : UINT32_MAX), callee_(cx), script_(cx) { if (frame_) { - start_ = SnapshotIterator(*frame_); + if (frame_->isBailoutIterator()) + start_ = SnapshotIterator(*frame_->asBailoutIterator()); + else + start_ = SnapshotIterator(*frame_); // findNextFrame will iterate to the next frame and init. everything. // Therefore to settle on the same frame, we report one frame less readed. framesRead_ = iter->framesRead_ - 1; findNextFrame(); } } @@ -2339,17 +2327,16 @@ JitFrameIterator::dump() const case JitFrame_BaselineJS: dumpBaseline(); break; case JitFrame_BaselineStub: case JitFrame_Unwound_BaselineStub: fprintf(stderr, " Baseline stub frame\n"); fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize())); break; - case JitFrame_Bailout: case JitFrame_IonJS: { InlineFrameIterator frames(GetJSContextFromJitCode(), this); for (;;) { frames.dump(); if (!frames.more()) break; ++frames;
--- a/js/src/jit/IonFrames.h +++ b/js/src/jit/IonFrames.h @@ -287,19 +287,19 @@ void UpdateJitActivationsForMinorGC(PerT static inline uint32_t MakeFrameDescriptor(uint32_t frameSize, FrameType type) { return (frameSize << FRAMESIZE_SHIFT) | type; } // Returns the JSScript associated with the topmost Ion frame. inline JSScript * -GetTopIonJSScript(ThreadSafeContext *cx, void **returnAddrOut = nullptr) +GetTopIonJSScript(uint8_t *jitTop, void **returnAddrOut, ExecutionMode mode) { - JitFrameIterator iter(cx); + JitFrameIterator iter(jitTop, mode); MOZ_ASSERT(iter.type() == JitFrame_Exit); ++iter; MOZ_ASSERT(iter.returnAddressToFp() != nullptr); if (returnAddrOut) *returnAddrOut = (void *) iter.returnAddressToFp(); if (iter.isBaselineStub()) {
--- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -52,63 +52,79 @@ enum FrameType // An unwound rectifier frame is a rectifier frame signalling that its callee // frame has been turned into an exit frame (see EnsureExitFrame). JitFrame_Unwound_Rectifier, // An exit frame is necessary for transitioning from a JS frame into C++. // From within C++, an exit frame is always the last frame in any // JitActivation. - JitFrame_Exit, - - // A bailout frame is a special IonJS jit frame after a bailout, and before - // the reconstruction of the BaselineJS frame. From within C++, a bailout - // frame is always the last frame in a JitActivation iff the bailout frame - // information is recorded on the JitActivation. - JitFrame_Bailout + JitFrame_Exit }; enum ReadFrameArgsBehavior { // Only read formals (i.e. [0 ... callee()->nargs] ReadFrame_Formals, // Only read overflown args (i.e. [callee()->nargs ... numActuals()] ReadFrame_Overflown, // Read all args (i.e. [0 ... numActuals()]) ReadFrame_Actuals }; class IonCommonFrameLayout; class IonJSFrameLayout; class IonExitFrameLayout; +class IonBailoutIterator; class BaselineFrame; class JitActivation; class JitFrameIterator { protected: uint8_t *current_; FrameType type_; uint8_t *returnAddressToFp_; size_t frameSize_; ExecutionMode mode_; + enum Kind { + Kind_FrameIterator, + Kind_BailoutIterator + } kind_; private: mutable const SafepointIndex *cachedSafepointIndex_; const JitActivation *activation_; void dumpBaseline() const; public: - explicit JitFrameIterator(); + explicit JitFrameIterator(uint8_t *top, ExecutionMode mode) + : current_(top), + type_(JitFrame_Exit), + returnAddressToFp_(nullptr), + frameSize_(0), + mode_(mode), + kind_(Kind_FrameIterator), + cachedSafepointIndex_(nullptr), + activation_(nullptr) + { } + explicit JitFrameIterator(ThreadSafeContext *cx); explicit JitFrameIterator(const ActivationIterator &activations); + explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode); + + bool isBailoutIterator() const { + return kind_ == Kind_BailoutIterator; + } + IonBailoutIterator *asBailoutIterator(); + const IonBailoutIterator *asBailoutIterator() const; // Current frame information. FrameType type() const { return type_; } uint8_t *fp() const { return current_; } @@ -117,45 +133,40 @@ class JitFrameIterator } IonCommonFrameLayout *current() const { return (IonCommonFrameLayout *)current_; } inline uint8_t *returnAddress() const; - // Return the pointer of the JitFrame, the iterator is assumed to be settled - // on a scripted frame. - IonJSFrameLayout *jsFrame() const; + IonJSFrameLayout *jsFrame() const { + MOZ_ASSERT(isScripted()); + return (IonJSFrameLayout *) fp(); + } // Returns true iff this exit frame was created using EnsureExitFrame. inline bool isFakeExitFrame() const; inline IonExitFrameLayout *exitFrame() const; // Returns whether the JS frame has been invalidated and, if so, // places the invalidated Ion script in |ionScript|. bool checkInvalidation(IonScript **ionScript) const; bool checkInvalidation() const; bool isScripted() const { - return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout; + return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS; } bool isBaselineJS() const { return type_ == JitFrame_BaselineJS; } - bool isIonScripted() const { - return type_ == JitFrame_IonJS || type_ == JitFrame_Bailout; - } bool isIonJS() const { return type_ == JitFrame_IonJS; } - bool isBailoutJS() const { - return type_ == JitFrame_Bailout; - } bool isBaselineStub() const { return type_ == JitFrame_BaselineStub; } bool isBareExit() const; template <typename T> bool isExitFrameLayout() const; bool isEntry() const { return type_ == JitFrame_Entry; @@ -211,20 +222,16 @@ class JitFrameIterator // Returns the Safepoint associated with this JS frame. Incurs a lookup // overhead. const SafepointIndex *safepoint() const; // Returns the OSI index associated with this JS frame. Incurs a lookup // overhead. const OsiIndex *osiIndex() const; - // Returns the Snapshot offset associated with this JS frame. Incurs a - // lookup overhead. - SnapshotOffset snapshotOffset() const; - uintptr_t *spillBase() const; MachineState machineState() const; template <class Op> void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const { MOZ_ASSERT(isBaselineJS()); unsigned nactual = numActualArgs(); @@ -464,16 +471,17 @@ class SnapshotIterator public: // Connect all informations about the current script in order to recover the // content of baseline frames. SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset, IonJSFrameLayout *fp, const MachineState &machine); explicit SnapshotIterator(const JitFrameIterator &iter); + explicit SnapshotIterator(const IonBailoutIterator &iter); SnapshotIterator(); Value read() { return allocationValue(readAllocation()); } Value maybeRead(MaybeReadFallback &fallback) { RValueAllocation a = readAllocation(); @@ -578,16 +586,17 @@ class InlineFrameIterator private: void findNextFrame(); JSObject *computeScopeChain(Value scopeChainValue) const; public: InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter); InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter); + InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter); InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter); bool more() const { return frame_ && framesRead_ < frameCount_; } JSFunction *callee() const { MOZ_ASSERT(callee_); return callee_;
--- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -539,18 +539,17 @@ jit::BailoutPar(BailoutStack *sp, uint8_ // We don't have an exit frame. MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) && IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000), "Fake jitTop pointer should be within the first page."); cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT; JitActivationIterator jitActivations(cx->perThreadData); - BailoutFrameInfo bailoutData(jitActivations, sp); - JitFrameIterator frameIter(jitActivations); + IonBailoutIterator frameIter(jitActivations, sp); SnapshotIterator snapIter(frameIter); cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind()); cx->bailoutRecord->rematerializeFrames(cx, frameIter); MOZ_ASSERT(frameIter.done()); *entryFramePointer = frameIter.fp(); }
--- a/js/src/jit/arm/Bailouts-arm.cpp +++ b/js/src/jit/arm/Bailouts-arm.cpp @@ -64,59 +64,63 @@ class BailoutStack }; // Make sure the compiler doesn't add extra padding. static_assert((sizeof(BailoutStack) % 8) == 0, "BailoutStack should be 8-byte aligned."); } // namespace jit } // namespace js -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - BailoutStack *bailout) - : machine_(bailout->machine()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + BailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); - framePointer_ = sp + bailout->frameSize(); - topFrameSize_ = framePointer_ - sp; + uint8_t *fp = sp + bailout->frameSize(); - JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken()); - JitActivation *activation = activations.activation()->asJit(); - if (activation->cx()->isForkJoinContext()) - topIonScript_ = script->parallelIonScript(); - else - topIonScript_ = script->ionScript(); - - attachOnJitActivation(activations); + kind_ = Kind_BailoutIterator; + current_ = fp; + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - sp; + switch (mode_) { + case SequentialExecution: topIonScript_ = script()->ionScript(); break; + case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break; + default: MOZ_CRASH("No such execution mode"); + } if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. + JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw())); MOZ_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); } -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - InvalidationBailoutStack *bailout) - : machine_(bailout->machine()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + InvalidationBailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machine()) { - framePointer_ = (uint8_t*) bailout->fp(); - topFrameSize_ = framePointer_ - bailout->sp(); + kind_ = Kind_BailoutIterator; + returnAddressToFp_ = bailout->osiPointReturnAddress(); topIonScript_ = bailout->ionScript(); - attachOnJitActivation(activations); + const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); - uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress(); - const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); + current_ = (uint8_t*) bailout->fp(); + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - bailout->sp(); snapshotOffset_ = osiIndex->snapshotOffset(); }
--- a/js/src/jit/mips/Bailouts-mips.cpp +++ b/js/src/jit/mips/Bailouts-mips.cpp @@ -7,59 +7,63 @@ #include "jit/mips/Bailouts-mips.h" #include "jscntxt.h" #include "jscompartment.h" using namespace js; using namespace js::jit; -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - BailoutStack *bailout) - : machine_(bailout->machine()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + BailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); - framePointer_ = sp + bailout->frameSize(); - topFrameSize_ = framePointer_ - sp; + uint8_t *fp = sp + bailout->frameSize(); - JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken()); - JitActivation *activation = activations.activation()->asJit(); - if (activation->cx()->isForkJoinContext()) - topIonScript_ = script->parallelIonScript(); - else - topIonScript_ = script->ionScript(); - - attachOnJitActivation(activations); + kind_ = Kind_BailoutIterator; + current_ = fp; + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - sp; + switch (mode_) { + case SequentialExecution: topIonScript_ = script()->ionScript(); break; + case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break; + default: MOZ_CRASH("No such execution mode"); + } if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. + JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw()); MOZ_ASSERT(tableOffset >= tableStart && - tableOffset < tableStart + code->instructionsSize()); + tableOffset < tableStart + code->instructionsSize()); MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); } -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - InvalidationBailoutStack *bailout) - : machine_(bailout->machine()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + InvalidationBailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machine()) { - framePointer_ = (uint8_t*) bailout->fp(); - topFrameSize_ = framePointer_ - bailout->sp(); + kind_ = Kind_BailoutIterator; + returnAddressToFp_ = bailout->osiPointReturnAddress(); topIonScript_ = bailout->ionScript(); - attachOnJitActivation(activations); + const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); - uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress(); - const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); + current_ = (uint8_t*) bailout->fp(); + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - bailout->sp(); snapshotOffset_ = osiIndex->snapshotOffset(); }
--- a/js/src/jit/none/Trampoline-none.cpp +++ b/js/src/jit/none/Trampoline-none.cpp @@ -42,22 +42,24 @@ void MacroAssembler::alignFrameForICArgu void MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive &) { MOZ_CRASH(); } const Register ABIArgGenerator::NonArgReturnReg0 = { 0 }; const Register ABIArgGenerator::NonArgReturnReg1 = { 0 }; const Register ABIArgGenerator::NonArg_VolatileReg = { 0 }; const Register ABIArgGenerator::NonReturn_VolatileReg0 = { 0 }; const Register ABIArgGenerator::NonReturn_VolatileReg1 = { 0 }; -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, BailoutStack *bailout) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, BailoutStack *bailout) + : JitFrameIterator(iter) { MOZ_CRASH(); } -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, InvalidationBailoutStack *bailout) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, InvalidationBailoutStack *bailout) + : JitFrameIterator(iter) { MOZ_CRASH(); } bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); } bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); } bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); } bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
--- a/js/src/jit/x64/Bailouts-x64.cpp +++ b/js/src/jit/x64/Bailouts-x64.cpp @@ -40,40 +40,43 @@ class BailoutStack } // namespace jit } // namespace js #if defined(_WIN32) # pragma pack(pop) #endif -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - BailoutStack *bailout) - : machine_(bailout->machineState()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + BailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machineState()) { uint8_t *sp = bailout->parentStackPointer(); - framePointer_ = sp + bailout->frameSize(); - topFrameSize_ = framePointer_ - sp; + uint8_t *fp = sp + bailout->frameSize(); - JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken()); - JitActivation *activation = activations.activation()->asJit(); - if (activation->cx()->isForkJoinContext()) - topIonScript_ = script->parallelIonScript(); - else - topIonScript_ = script->ionScript(); - - attachOnJitActivation(activations); + kind_ = Kind_BailoutIterator; + current_ = fp; + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - sp; + switch (mode_) { + case SequentialExecution: topIonScript_ = script()->ionScript(); break; + case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break; + default: MOZ_CRASH("No such execution mode"); + } snapshotOffset_ = bailout->snapshotOffset(); } -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - InvalidationBailoutStack *bailout) - : machine_(bailout->machine()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + InvalidationBailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machine()) { - framePointer_ = (uint8_t*) bailout->fp(); - topFrameSize_ = framePointer_ - bailout->sp(); + kind_ = Kind_BailoutIterator; + returnAddressToFp_ = bailout->osiPointReturnAddress(); topIonScript_ = bailout->ionScript(); - attachOnJitActivation(activations); + const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); - uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress(); - const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); + current_ = (uint8_t*) bailout->fp(); + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - bailout->sp(); snapshotOffset_ = osiIndex->snapshotOffset(); }
--- a/js/src/jit/x86/Bailouts-x86.cpp +++ b/js/src/jit/x86/Bailouts-x86.cpp @@ -60,59 +60,63 @@ class BailoutStack } // namespace jit } // namespace js #if defined(_WIN32) # pragma pack(pop) #endif -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - BailoutStack *bailout) - : machine_(bailout->machine()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + BailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); - framePointer_ = sp + bailout->frameSize(); - topFrameSize_ = framePointer_ - sp; + uint8_t *fp = sp + bailout->frameSize(); - JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken()); - JitActivation *activation = activations.activation()->asJit(); - if (activation->cx()->isForkJoinContext()) - topIonScript_ = script->parallelIonScript(); - else - topIonScript_ = script->ionScript(); - - attachOnJitActivation(activations); + kind_ = Kind_BailoutIterator; + current_ = fp; + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - sp; + switch (mode_) { + case SequentialExecution: topIonScript_ = script()->ionScript(); break; + case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break; + default: MOZ_CRASH("No such execution mode"); + } if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. + JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw()); MOZ_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); } -BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, - InvalidationBailoutStack *bailout) - : machine_(bailout->machine()) +IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, + InvalidationBailoutStack *bailout) + : JitFrameIterator(activations), + machine_(bailout->machine()) { - framePointer_ = (uint8_t*) bailout->fp(); - topFrameSize_ = framePointer_ - bailout->sp(); + kind_ = Kind_BailoutIterator; + returnAddressToFp_ = bailout->osiPointReturnAddress(); topIonScript_ = bailout->ionScript(); - attachOnJitActivation(activations); + const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); - uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress(); - const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); + current_ = (uint8_t*) bailout->fp(); + type_ = JitFrame_IonJS; + topFrameSize_ = current_ - bailout->sp(); snapshotOffset_ = osiIndex->snapshotOffset(); }
--- a/js/src/vm/ForkJoin.cpp +++ b/js/src/vm/ForkJoin.cpp @@ -1876,51 +1876,66 @@ ParallelBailoutRecord::init(JSContext *c void ParallelBailoutRecord::reset() { RematerializedFrame::FreeInVector(frames()); cause = ParallelBailoutNone; } -void -ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter) +template <class T> +static void +RematerializeFramesWithIter(ForkJoinContext *cx, T &frameIter, + Vector<RematerializedFrame *> &frames) { - // This function is infallible. These are only called when we are already - // erroring out. If we OOM here, free what we've allocated and return. Error - // reporting is then unable to give the user detailed stack information. + // This function as well as |rematerializeFrames| methods below are + // infallible. These are only called when we are already erroring out. If + // we OOM here, free what we've allocated and return. Error reporting is + // then unable to give the user detailed stack information. - MOZ_ASSERT(frames().empty()); + MOZ_ASSERT(frames.empty()); for (; !frameIter.done(); ++frameIter) { if (!frameIter.isIonJS()) continue; InlineFrameIterator inlineIter(cx, &frameIter); Vector<RematerializedFrame *> inlineFrames(cx); if (!RematerializedFrame::RematerializeInlineFrames(cx, frameIter.fp(), inlineIter, inlineFrames)) { RematerializedFrame::FreeInVector(inlineFrames); - RematerializedFrame::FreeInVector(frames()); + RematerializedFrame::FreeInVector(frames); return; } // Reverse the inline frames into the main vector. while (!inlineFrames.empty()) { - if (!frames().append(inlineFrames.popCopy())) { + if (!frames.append(inlineFrames.popCopy())) { RematerializedFrame::FreeInVector(inlineFrames); - RematerializedFrame::FreeInVector(frames()); + RematerializedFrame::FreeInVector(frames); return; } } } } +void +ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter) +{ + RematerializeFramesWithIter(cx, frameIter, frames()); +} + +void +ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, IonBailoutIterator &frameIter) +{ + RematerializeFramesWithIter(cx, frameIter, frames()); +} + ////////////////////////////////////////////////////////////////////////////// // // Debug spew // #ifdef FORKJOIN_SPEW
--- a/js/src/vm/ForkJoin.h +++ b/js/src/vm/ForkJoin.h @@ -321,16 +321,17 @@ enum ParallelBailoutCause { // parallel. ParallelBailoutRequestedGC, ParallelBailoutRequestedZoneGC }; namespace jit { class BailoutStack; class JitFrameIterator; +class IonBailoutIterator; class RematerializedFrame; } // See "Bailouts" section in comment above. struct ParallelBailoutRecord { // Captured Ion frames at the point of bailout. Stored younger-to-older, // i.e., the 0th frame is the youngest frame. @@ -367,16 +368,17 @@ struct ParallelBailoutRecord } void setIonBailoutKind(jit::BailoutKind kind) { joinCause(ParallelBailoutExecution); ionBailoutKind = kind; } void rematerializeFrames(ForkJoinContext *cx, jit::JitFrameIterator &frameIter); + void rematerializeFrames(ForkJoinContext *cx, jit::IonBailoutIterator &frameIter); }; class ForkJoinShared; class ForkJoinContext : public ThreadSafeContext { public: // Bailout record used to record the reason this thread stopped executing
--- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -346,25 +346,16 @@ FrameIter::unaliasedForEachActual(JSCont break; case INTERP: interpFrame()->unaliasedForEachActual(op); return; case JIT: if (data_.jitFrames_.isIonJS()) { jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_); ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover); - } else if (data_.jitFrames_.isBailoutJS()) { - // :TODO: (Bug 1070962) If we are introspecting the frame which is - // being bailed, then we might be in the middle of recovering - // instructions. Stacking computeInstructionResults implies that we - // might be recovering result twice. In the mean time, to avoid - // that, we just return Undefined values for instruction results - // which are not yet recovered. - jit::MaybeReadFallback fallback; - ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, fallback); } else { MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals); } return; } MOZ_CRASH("Unexpected state"); }
--- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -623,17 +623,17 @@ FrameIter::Data::Data(ThreadSafeContext ContextOption contextOption, JSPrincipals *principals) : cx_(cx), savedOption_(savedOption), contextOption_(contextOption), principals_(principals), pc_(nullptr), interpFrames_(nullptr), activations_(cx->perThreadData), - jitFrames_(), + jitFrames_((uint8_t *)nullptr, SequentialExecution), ionInlineFrameNo_(0), asmJSFrames_() { } FrameIter::Data::Data(const FrameIter::Data &other) : cx_(other.cx_), savedOption_(other.savedOption_), @@ -674,50 +674,50 @@ FrameIter::FrameIter(JSContext *cx, Cont ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr) { settleOnActivation(); } FrameIter::FrameIter(const FrameIter &other) : data_(other.data_), ionInlineFrames_(other.data_.cx_, - data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr) + data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr) { } FrameIter::FrameIter(const Data &data) : data_(data), - ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr) + ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr) { MOZ_ASSERT(data.cx_); - if (data_.jitFrames_.isIonScripted()) { + if (data_.jitFrames_.isIonJS()) { while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_) ++ionInlineFrames_; } } void FrameIter::nextJitFrame() { - if (data_.jitFrames_.isIonScripted()) { + if (data_.jitFrames_.isIonJS()) { ionInlineFrames_.resetOn(&data_.jitFrames_); data_.pc_ = ionInlineFrames_.pc(); } else { MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_); } } void FrameIter::popJitFrame() { MOZ_ASSERT(data_.state_ == JIT); - if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) { + if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) { ++ionInlineFrames_; data_.pc_ = ionInlineFrames_.pc(); return; } ++data_.jitFrames_; while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted()) ++data_.jitFrames_; @@ -784,17 +784,17 @@ FrameIter::operator++() return *this; } FrameIter::Data * FrameIter::copyData() const { Data *data = data_.cx_->new_<Data>(data_); MOZ_ASSERT(data_.state_ != ASMJS); - if (data && data_.jitFrames_.isIonScripted()) + if (data && data_.jitFrames_.isIonJS()) data->ionInlineFrameNo_ = ionInlineFrames_.frameNo(); return data; } AbstractFramePtr FrameIter::copyDataAsAbstractFramePtr() const { AbstractFramePtr frame; @@ -992,17 +992,17 @@ FrameIter::mutedErrors() const bool FrameIter::isConstructing() const { switch (data_.state_) { case DONE: case ASMJS: break; case JIT: - if (data_.jitFrames_.isIonScripted()) + if (data_.jitFrames_.isIonJS()) return ionInlineFrames_.isConstructing(); MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); return data_.jitFrames_.isConstructing(); case INTERP: return interpFrame()->isConstructing(); } MOZ_CRASH("Unexpected state"); @@ -1021,17 +1021,17 @@ FrameIter::hasUsableAbstractFramePtr() c switch (data_.state_) { case DONE: case ASMJS: return false; case JIT: if (data_.jitFrames_.isBaselineJS()) return true; - MOZ_ASSERT(data_.jitFrames_.isIonScripted()); + MOZ_ASSERT(data_.jitFrames_.isIonJS()); return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(), ionInlineFrames_.frameNo()); break; case INTERP: return true; } MOZ_CRASH("Unexpected state"); } @@ -1043,17 +1043,17 @@ FrameIter::abstractFramePtr() const switch (data_.state_) { case DONE: case ASMJS: break; case JIT: { if (data_.jitFrames_.isBaselineJS()) return data_.jitFrames_.baselineFrame(); - MOZ_ASSERT(data_.jitFrames_.isIonScripted()); + MOZ_ASSERT(data_.jitFrames_.isIonJS()); return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(), ionInlineFrames_.frameNo()); break; } case INTERP: MOZ_ASSERT(interpFrame()); return AbstractFramePtr(interpFrame()); } @@ -1115,17 +1115,17 @@ FrameIter::callee() const case ASMJS: break; case INTERP: MOZ_ASSERT(isFunctionFrame()); return &interpFrame()->callee(); case JIT: if (data_.jitFrames_.isBaselineJS()) return data_.jitFrames_.callee(); - MOZ_ASSERT(data_.jitFrames_.isIonScripted()); + MOZ_ASSERT(data_.jitFrames_.isIonJS()); return ionInlineFrames_.callee(); } MOZ_CRASH("Unexpected state"); } Value FrameIter::calleev() const { @@ -1148,17 +1148,17 @@ FrameIter::numActualArgs() const switch (data_.state_) { case DONE: case ASMJS: break; case INTERP: MOZ_ASSERT(isFunctionFrame()); return interpFrame()->numActualArgs(); case JIT: - if (data_.jitFrames_.isIonScripted()) + if (data_.jitFrames_.isIonJS()) return ionInlineFrames_.numActualArgs(); MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); return data_.jitFrames_.numActualArgs(); } MOZ_CRASH("Unexpected state"); } @@ -1177,17 +1177,17 @@ FrameIter::unaliasedActual(unsigned i, M JSObject * FrameIter::scopeChain() const { switch (data_.state_) { case DONE: case ASMJS: break; case JIT: - if (data_.jitFrames_.isIonScripted()) + if (data_.jitFrames_.isIonJS()) return ionInlineFrames_.scopeChain(); return data_.jitFrames_.baselineFrame()->scopeChain(); case INTERP: return interpFrame()->scopeChain(); } MOZ_CRASH("Unexpected state"); } @@ -1232,17 +1232,17 @@ FrameIter::computedThisValue() const Value FrameIter::thisv(JSContext *cx) { switch (data_.state_) { case DONE: case ASMJS: break; case JIT: - if (data_.jitFrames_.isIonScripted()) { + if (data_.jitFrames_.isIonJS()) { jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_); return ionInlineFrames_.thisValue(recover); } return data_.jitFrames_.baselineFrame()->thisValue(); case INTERP: return interpFrame()->thisValue(); } MOZ_CRASH("Unexpected state"); @@ -1288,17 +1288,17 @@ FrameIter::setReturnValue(const Value &v size_t FrameIter::numFrameSlots() const { switch (data_.state_) { case DONE: case ASMJS: break; case JIT: { - if (data_.jitFrames_.isIonScripted()) { + if (data_.jitFrames_.isIonJS()) { return ionInlineFrames_.snapshotIterator().numAllocations() - ionInlineFrames_.script()->nfixed(); } jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame(); return frame->numValueSlots() - data_.jitFrames_.script()->nfixed(); } case INTERP: MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base()); @@ -1310,17 +1310,17 @@ FrameIter::numFrameSlots() const Value FrameIter::frameSlotValue(size_t index) const { switch (data_.state_) { case DONE: case ASMJS: break; case JIT: - if (data_.jitFrames_.isIonScripted()) { + if (data_.jitFrames_.isIonJS()) { jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator()); index += ionInlineFrames_.script()->nfixed(); return si.maybeReadAllocByIndex(index); } index += data_.jitFrames_.script()->nfixed(); return *data_.jitFrames_.baselineFrame()->valueSlot(index); case INTERP: @@ -1399,73 +1399,52 @@ js::CheckLocalUnaliased(MaybeCheckAliasi } } #endif jit::JitActivation::JitActivation(JSContext *cx, bool active) : Activation(cx, Jit), active_(active), rematerializedFrames_(nullptr), - ionRecovery_(cx), - bailoutData_(nullptr) + ionRecovery_(cx) { if (active) { prevJitTop_ = cx->mainThread().jitTop; prevJitJSContext_ = cx->mainThread().jitJSContext; cx->mainThread().jitJSContext = cx; } else { prevJitTop_ = nullptr; prevJitJSContext_ = nullptr; } } jit::JitActivation::JitActivation(ForkJoinContext *cx) : Activation(cx, Jit), active_(true), rematerializedFrames_(nullptr), - ionRecovery_(cx), - bailoutData_(nullptr) + ionRecovery_(cx) { prevJitTop_ = cx->perThreadData->jitTop; prevJitJSContext_ = cx->perThreadData->jitJSContext; cx->perThreadData->jitJSContext = nullptr; } jit::JitActivation::~JitActivation() { if (active_) { cx_->perThreadData->jitTop = prevJitTop_; cx_->perThreadData->jitJSContext = prevJitJSContext_; } + clearRematerializedFrames(); // All reocvered value are taken from activation during the bailout. MOZ_ASSERT(ionRecovery_.empty()); - - // The BailoutFrameInfo should have unregistered itself from the - // JitActivations. - MOZ_ASSERT(!bailoutData_); - - clearRematerializedFrames(); js_delete(rematerializedFrames_); } -void -jit::JitActivation::setBailoutData(jit::BailoutFrameInfo *bailoutData) -{ - MOZ_ASSERT(!bailoutData_); - bailoutData_ = bailoutData; -} - -void -jit::JitActivation::cleanBailoutData() -{ - MOZ_ASSERT(bailoutData_); - bailoutData_ = nullptr; -} - // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable // and disable activation instruction sequences. void jit::JitActivation::setActive(JSContext *cx, bool active) { // Only allowed to deactivate/activate if activation is top. // (Not tested and will probably fail in other situations.) @@ -1502,23 +1481,24 @@ jit::JitActivation::clearRematerializedF return; for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) { RematerializedFrame::FreeInVector(e.front().value()); e.removeFront(); } } +template <class T> jit::RematerializedFrame * -jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter, size_t inlineDepth) +jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const T &iter, size_t inlineDepth) { // Only allow rematerializing from the same thread. MOZ_ASSERT(cx->perThreadData == cx_->perThreadData); MOZ_ASSERT(iter.activation() == this); - MOZ_ASSERT(iter.isIonScripted()); + MOZ_ASSERT(iter.isIonJS()); if (!rematerializedFrames_) { rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx); if (!rematerializedFrames_ || !rematerializedFrames_->init()) { rematerializedFrames_ = nullptr; return nullptr; } } @@ -1538,16 +1518,25 @@ jit::JitActivation::getRematerializedFra InlineFrameIterator inlineIter(cx, &iter); if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, p->value())) return nullptr; } return p->value()[inlineDepth]; } +template jit::RematerializedFrame * +jit::JitActivation::getRematerializedFrame<jit::JitFrameIterator>(ThreadSafeContext *cx, + const jit::JitFrameIterator &iter, + size_t inlineDepth); +template jit::RematerializedFrame * +jit::JitActivation::getRematerializedFrame<jit::IonBailoutIterator>(ThreadSafeContext *cx, + const jit::IonBailoutIterator &iter, + size_t inlineDepth); + jit::RematerializedFrame * jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth) { if (!rematerializedFrames_) return nullptr; if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr; return nullptr;
--- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1296,18 +1296,16 @@ class ActivationIterator } bool done() const { return activation_ == nullptr; } }; namespace jit { -class BailoutFrameInfo; - // A JitActivation is used for frames running in Baseline or Ion. class JitActivation : public Activation { uint8_t *prevJitTop_; JSContext *prevJitJSContext_; bool active_; // Rematerialized Ion frames which has info copied out of snapshots. Maps @@ -1324,23 +1322,16 @@ class JitActivation : public Activation // // RInstructionResults are appended into this vector when Snapshot values // have to be read, or when the evaluation has to run before some mutating // code. Each RInstructionResults belongs to one frame which has to bailout // as soon as we get back to it. typedef Vector<RInstructionResults, 1> IonRecoveryMap; IonRecoveryMap ionRecovery_; - // If we are bailing out from Ion, then this field should be a non-null - // pointer which references the BailoutFrameInfo used to walk the inner - // frames. This field is used for all newly constructed JitFrameIterators to - // read the innermost frame information from this bailout data instead of - // reading it from the stack. - BailoutFrameInfo *bailoutData_; - void clearRematerializedFrames(); #ifdef CHECK_OSIPOINT_REGISTERS protected: // Used to verify that live registers don't change between a VM call and // the OsiPoint that follows it. Protected to silence Clang warning. uint32_t checkRegs_; RegisterDump regs_; @@ -1386,18 +1377,21 @@ class JitActivation : public Activation } #endif // Look up a rematerialized frame keyed by the fp, rematerializing the // frame if one doesn't already exist. A frame can only be rematerialized // if an IonFrameIterator pointing to the nearest uninlined frame can be // provided, as values need to be read out of snapshots. // + // T is either JitFrameIterator or IonBailoutIterator. + // // The inlineDepth must be within bounds of the frame pointed to by iter. - RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter, + template <class T> + RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const T &iter, size_t inlineDepth = 0); // Look up a rematerialized frame by the fp. If inlineDepth is out of // bounds of what has been rematerialized, nullptr is returned. RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0); bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) { return !!lookupRematerializedFrame(top, inlineDepth); @@ -1416,25 +1410,16 @@ class JitActivation : public Activation RInstructionResults *maybeIonFrameRecovery(IonJSFrameLayout *fp); // If an Ion frame recovery exists for the |fp| frame exists on the // activation, then move its content to the |results| argument, and remove // it from the activation. void maybeTakeIonFrameRecovery(IonJSFrameLayout *fp, RInstructionResults *results); void markIonRecovery(JSTracer *trc); - - // Return the bailout information if it is registered. - const BailoutFrameInfo *bailoutData() const { return bailoutData_; } - - // Register the bailout data when it is constructed. - void setBailoutData(BailoutFrameInfo *bailoutData); - - // Unregister the bailout data when the frame is reconstructed. - void cleanBailoutData(); }; // A filtering of the ActivationIterator to only stop at JitActivations. class JitActivationIterator : public ActivationIterator { void settle() { while (!done() && !activation_->isJit()) ActivationIterator::operator++();