Bug 1070962 part 4 - JitFrameIterator use BailoutData when it starts on a bailout frame. r=jandem

This commit is contained in:
Nicolas B. Pierron 2014-10-13 17:34:00 +02:00
parent bf282ccb9b
commit 85d9fdb3b3
6 changed files with 101 additions and 26 deletions

View File

@ -2702,9 +2702,16 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool
break; break;
case JitFrame_BaselineJS: case JitFrame_BaselineJS:
case JitFrame_IonJS: case JitFrame_IonJS:
case JitFrame_Bailout:
{ {
MOZ_ASSERT(it.isScripted()); MOZ_ASSERT(it.isScripted());
const char *type = it.isIonJS() ? "Optimized" : "Baseline"; const char *type = "Unknown";
if (it.isIonJS())
type = "Optimized";
else if (it.isBaselineJS())
type = "Baseline";
else if (it.isBailoutJS())
type = "Bailing";
JitSpew(JitSpew_IonInvalidate, "#%d %s JS frame @ %p, %s:%d (fun: %p, script: %p, pc %p)", 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(), frameno, type, it.fp(), it.script()->filename(), it.script()->lineno(),
it.maybeCallee(), (JSScript *)it.script(), it.returnAddressToFp()); it.maybeCallee(), (JSScript *)it.script(), it.returnAddressToFp());

View File

@ -102,6 +102,10 @@ JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx)
cachedSafepointIndex_(nullptr), cachedSafepointIndex_(nullptr),
activation_(cx->perThreadData->activation()->asJit()) activation_(cx->perThreadData->activation()->asJit())
{ {
if (activation_->bailoutData()) {
current_ = activation_->bailoutData()->fp();
type_ = JitFrame_Bailout;
}
} }
JitFrameIterator::JitFrameIterator(const ActivationIterator &activations) JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
@ -115,6 +119,10 @@ JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
cachedSafepointIndex_(nullptr), cachedSafepointIndex_(nullptr),
activation_(activations->asJit()) activation_(activations->asJit())
{ {
if (activation_->bailoutData()) {
current_ = activation_->bailoutData()->fp();
type_ = JitFrame_Bailout;
}
} }
IonBailoutIterator * IonBailoutIterator *
@ -275,6 +283,7 @@ SizeOfFramePrefix(FrameType type)
return IonEntryFrameLayout::Size(); return IonEntryFrameLayout::Size();
case JitFrame_BaselineJS: case JitFrame_BaselineJS:
case JitFrame_IonJS: case JitFrame_IonJS:
case JitFrame_Bailout:
case JitFrame_Unwound_IonJS: case JitFrame_Unwound_IonJS:
return IonJSFrameLayout::Size(); return IonJSFrameLayout::Size();
case JitFrame_BaselineStub: case JitFrame_BaselineStub:
@ -339,6 +348,8 @@ JitFrameIterator::operator++()
uintptr_t * uintptr_t *
JitFrameIterator::spillBase() const JitFrameIterator::spillBase() const
{ {
MOZ_ASSERT(isIonJS());
// Get the base address to where safepoint registers are spilled. // Get the base address to where safepoint registers are spilled.
// Out-of-line calls do not unwind the extra padding space used to // Out-of-line calls do not unwind the extra padding space used to
// aggregate bailout tables, so we use frameSize instead of frameLocals, // aggregate bailout tables, so we use frameSize instead of frameLocals,
@ -349,6 +360,12 @@ JitFrameIterator::spillBase() const
MachineState MachineState
JitFrameIterator::machineState() const 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()); SafepointReader reader(ionScript(), safepoint());
uintptr_t *spill = spillBase(); uintptr_t *spill = spillBase();
@ -1532,7 +1549,7 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot
SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter) SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
: snapshot_(iter.ionScript()->snapshots(), : snapshot_(iter.ionScript()->snapshots(),
iter.osiIndex()->snapshotOffset(), iter.snapshotOffset(),
iter.ionScript()->snapshotsRVATableSize(), iter.ionScript()->snapshotsRVATableSize(),
iter.ionScript()->snapshotsListSize()), iter.ionScript()->snapshotsListSize()),
recover_(snapshot_, recover_(snapshot_,
@ -1916,10 +1933,22 @@ SnapshotIterator::maybeReadAllocByIndex(size_t index)
return s; return s;
} }
IonJSFrameLayout *
JitFrameIterator::jsFrame() const
{
MOZ_ASSERT(isScripted());
if (isBailoutJS())
return activation_->bailoutData()->jsFrame();
return (IonJSFrameLayout *) fp();
}
IonScript * IonScript *
JitFrameIterator::ionScript() const JitFrameIterator::ionScript() const
{ {
MOZ_ASSERT(type() == JitFrame_IonJS); MOZ_ASSERT(isIonScripted());
if (isBailoutJS())
return activation_->bailoutData()->ionScript();
IonScript *ionScript = nullptr; IonScript *ionScript = nullptr;
if (checkInvalidation(&ionScript)) if (checkInvalidation(&ionScript))
@ -1930,7 +1959,7 @@ JitFrameIterator::ionScript() const
IonScript * IonScript *
JitFrameIterator::ionScriptFromCalleeToken() const JitFrameIterator::ionScriptFromCalleeToken() const
{ {
MOZ_ASSERT(type() == JitFrame_IonJS); MOZ_ASSERT(isIonJS());
MOZ_ASSERT(!checkInvalidation()); MOZ_ASSERT(!checkInvalidation());
switch (mode_) { switch (mode_) {
@ -1946,14 +1975,25 @@ JitFrameIterator::ionScriptFromCalleeToken() const
const SafepointIndex * const SafepointIndex *
JitFrameIterator::safepoint() const JitFrameIterator::safepoint() const
{ {
MOZ_ASSERT(isIonJS());
if (!cachedSafepointIndex_) if (!cachedSafepointIndex_)
cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp()); cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp());
return cachedSafepointIndex_; return cachedSafepointIndex_;
} }
SnapshotOffset
JitFrameIterator::snapshotOffset() const
{
MOZ_ASSERT(isIonScripted());
if (isBailoutJS())
return activation_->bailoutData()->snapshotOffset();
return osiIndex()->snapshotOffset();
}
const OsiIndex * const OsiIndex *
JitFrameIterator::osiIndex() const JitFrameIterator::osiIndex() const
{ {
MOZ_ASSERT(isIonJS());
SafepointReader reader(ionScript(), safepoint()); SafepointReader reader(ionScript(), safepoint());
return ionScript()->getOsiIndex(reader.osiReturnPointOffset()); return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
} }
@ -2335,6 +2375,7 @@ JitFrameIterator::dump() const
fprintf(stderr, " Baseline stub frame\n"); fprintf(stderr, " Baseline stub frame\n");
fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize())); fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
break; break;
case JitFrame_Bailout:
case JitFrame_IonJS: case JitFrame_IonJS:
{ {
InlineFrameIterator frames(GetJSContextFromJitCode(), this); InlineFrameIterator frames(GetJSContextFromJitCode(), this);

View File

@ -57,7 +57,13 @@ enum FrameType
// An exit frame is necessary for transitioning from a JS frame into C++. // 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 // From within C++, an exit frame is always the last frame in any
// JitActivation. // JitActivation.
JitFrame_Exit 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
}; };
enum ReadFrameArgsBehavior { enum ReadFrameArgsBehavior {
@ -127,10 +133,9 @@ class JitFrameIterator
inline uint8_t *returnAddress() const; inline uint8_t *returnAddress() const;
IonJSFrameLayout *jsFrame() const { // Return the pointer of the JitFrame, the iterator is assumed to be settled
MOZ_ASSERT(isScripted()); // on a scripted frame.
return (IonJSFrameLayout *) fp(); IonJSFrameLayout *jsFrame() const;
}
// Returns true iff this exit frame was created using EnsureExitFrame. // Returns true iff this exit frame was created using EnsureExitFrame.
inline bool isFakeExitFrame() const; inline bool isFakeExitFrame() const;
@ -143,14 +148,20 @@ class JitFrameIterator
bool checkInvalidation() const; bool checkInvalidation() const;
bool isScripted() const { bool isScripted() const {
return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS; return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
} }
bool isBaselineJS() const { bool isBaselineJS() const {
return type_ == JitFrame_BaselineJS; return type_ == JitFrame_BaselineJS;
} }
bool isIonScripted() const {
return type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
}
bool isIonJS() const { bool isIonJS() const {
return type_ == JitFrame_IonJS; return type_ == JitFrame_IonJS;
} }
bool isBailoutJS() const {
return type_ == JitFrame_Bailout;
}
bool isBaselineStub() const { bool isBaselineStub() const {
return type_ == JitFrame_BaselineStub; return type_ == JitFrame_BaselineStub;
} }
@ -216,6 +227,10 @@ class JitFrameIterator
// overhead. // overhead.
const OsiIndex *osiIndex() const; const OsiIndex *osiIndex() const;
// Returns the Snapshot offset associated with this JS frame. Incurs a
// lookup overhead.
SnapshotOffset snapshotOffset() const;
uintptr_t *spillBase() const; uintptr_t *spillBase() const;
MachineState machineState() const; MachineState machineState() const;

View File

@ -351,6 +351,15 @@ FrameIter::unaliasedForEachActual(JSContext *cx, Op op)
if (data_.jitFrames_.isIonJS()) { if (data_.jitFrames_.isIonJS()) {
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_); jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover); 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 { } else {
MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals); data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals);

View File

@ -679,17 +679,17 @@ FrameIter::FrameIter(JSContext *cx, ContextOption contextOption,
FrameIter::FrameIter(const FrameIter &other) FrameIter::FrameIter(const FrameIter &other)
: data_(other.data_), : data_(other.data_),
ionInlineFrames_(other.data_.cx_, ionInlineFrames_(other.data_.cx_,
data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr) data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr)
{ {
} }
FrameIter::FrameIter(const Data &data) FrameIter::FrameIter(const Data &data)
: data_(data), : data_(data),
ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr) ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr)
{ {
MOZ_ASSERT(data.cx_); MOZ_ASSERT(data.cx_);
if (data_.jitFrames_.isIonJS()) { if (data_.jitFrames_.isIonScripted()) {
while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_) while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
++ionInlineFrames_; ++ionInlineFrames_;
} }
@ -698,7 +698,7 @@ FrameIter::FrameIter(const Data &data)
void void
FrameIter::nextJitFrame() FrameIter::nextJitFrame()
{ {
if (data_.jitFrames_.isIonJS()) { if (data_.jitFrames_.isIonScripted()) {
ionInlineFrames_.resetOn(&data_.jitFrames_); ionInlineFrames_.resetOn(&data_.jitFrames_);
data_.pc_ = ionInlineFrames_.pc(); data_.pc_ = ionInlineFrames_.pc();
} else { } else {
@ -712,7 +712,7 @@ FrameIter::popJitFrame()
{ {
MOZ_ASSERT(data_.state_ == JIT); MOZ_ASSERT(data_.state_ == JIT);
if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) { if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) {
++ionInlineFrames_; ++ionInlineFrames_;
data_.pc_ = ionInlineFrames_.pc(); data_.pc_ = ionInlineFrames_.pc();
return; return;
@ -789,7 +789,7 @@ FrameIter::copyData() const
{ {
Data *data = data_.cx_->new_<Data>(data_); Data *data = data_.cx_->new_<Data>(data_);
MOZ_ASSERT(data_.state_ != ASMJS); MOZ_ASSERT(data_.state_ != ASMJS);
if (data && data_.jitFrames_.isIonJS()) if (data && data_.jitFrames_.isIonScripted())
data->ionInlineFrameNo_ = ionInlineFrames_.frameNo(); data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
return data; return data;
} }
@ -997,7 +997,7 @@ FrameIter::isConstructing() const
case ASMJS: case ASMJS:
break; break;
case JIT: case JIT:
if (data_.jitFrames_.isIonJS()) if (data_.jitFrames_.isIonScripted())
return ionInlineFrames_.isConstructing(); return ionInlineFrames_.isConstructing();
MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
return data_.jitFrames_.isConstructing(); return data_.jitFrames_.isConstructing();
@ -1026,7 +1026,7 @@ FrameIter::hasUsableAbstractFramePtr() const
if (data_.jitFrames_.isBaselineJS()) if (data_.jitFrames_.isBaselineJS())
return true; return true;
MOZ_ASSERT(data_.jitFrames_.isIonJS()); MOZ_ASSERT(data_.jitFrames_.isIonScripted());
return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(), return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
ionInlineFrames_.frameNo()); ionInlineFrames_.frameNo());
break; break;
@ -1048,7 +1048,7 @@ FrameIter::abstractFramePtr() const
if (data_.jitFrames_.isBaselineJS()) if (data_.jitFrames_.isBaselineJS())
return data_.jitFrames_.baselineFrame(); return data_.jitFrames_.baselineFrame();
MOZ_ASSERT(data_.jitFrames_.isIonJS()); MOZ_ASSERT(data_.jitFrames_.isIonScripted());
return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(), return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
ionInlineFrames_.frameNo()); ionInlineFrames_.frameNo());
break; break;
@ -1120,7 +1120,7 @@ FrameIter::callee() const
case JIT: case JIT:
if (data_.jitFrames_.isBaselineJS()) if (data_.jitFrames_.isBaselineJS())
return data_.jitFrames_.callee(); return data_.jitFrames_.callee();
MOZ_ASSERT(data_.jitFrames_.isIonJS()); MOZ_ASSERT(data_.jitFrames_.isIonScripted());
return ionInlineFrames_.callee(); return ionInlineFrames_.callee();
} }
MOZ_CRASH("Unexpected state"); MOZ_CRASH("Unexpected state");
@ -1153,7 +1153,7 @@ FrameIter::numActualArgs() const
MOZ_ASSERT(isFunctionFrame()); MOZ_ASSERT(isFunctionFrame());
return interpFrame()->numActualArgs(); return interpFrame()->numActualArgs();
case JIT: case JIT:
if (data_.jitFrames_.isIonJS()) if (data_.jitFrames_.isIonScripted())
return ionInlineFrames_.numActualArgs(); return ionInlineFrames_.numActualArgs();
MOZ_ASSERT(data_.jitFrames_.isBaselineJS()); MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
@ -1182,7 +1182,7 @@ FrameIter::scopeChain() const
case ASMJS: case ASMJS:
break; break;
case JIT: case JIT:
if (data_.jitFrames_.isIonJS()) if (data_.jitFrames_.isIonScripted())
return ionInlineFrames_.scopeChain(); return ionInlineFrames_.scopeChain();
return data_.jitFrames_.baselineFrame()->scopeChain(); return data_.jitFrames_.baselineFrame()->scopeChain();
case INTERP: case INTERP:
@ -1237,7 +1237,7 @@ FrameIter::thisv(JSContext *cx)
case ASMJS: case ASMJS:
break; break;
case JIT: case JIT:
if (data_.jitFrames_.isIonJS()) { if (data_.jitFrames_.isIonScripted()) {
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_); jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
return ionInlineFrames_.thisValue(recover); return ionInlineFrames_.thisValue(recover);
} }
@ -1293,7 +1293,7 @@ FrameIter::numFrameSlots() const
case ASMJS: case ASMJS:
break; break;
case JIT: { case JIT: {
if (data_.jitFrames_.isIonJS()) { if (data_.jitFrames_.isIonScripted()) {
return ionInlineFrames_.snapshotIterator().numAllocations() - return ionInlineFrames_.snapshotIterator().numAllocations() -
ionInlineFrames_.script()->nfixed(); ionInlineFrames_.script()->nfixed();
} }
@ -1315,7 +1315,7 @@ FrameIter::frameSlotValue(size_t index) const
case ASMJS: case ASMJS:
break; break;
case JIT: case JIT:
if (data_.jitFrames_.isIonJS()) { if (data_.jitFrames_.isIonScripted()) {
jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator()); jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
index += ionInlineFrames_.script()->nfixed(); index += ionInlineFrames_.script()->nfixed();
return si.maybeReadAllocByIndex(index); return si.maybeReadAllocByIndex(index);
@ -1514,7 +1514,7 @@ jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const T &iter,
// Only allow rematerializing from the same thread. // Only allow rematerializing from the same thread.
MOZ_ASSERT(cx->perThreadData == cx_->perThreadData); MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
MOZ_ASSERT(iter.activation() == this); MOZ_ASSERT(iter.activation() == this);
MOZ_ASSERT(iter.isIonJS()); MOZ_ASSERT(iter.isIonScripted());
if (!rematerializedFrames_) { if (!rematerializedFrames_) {
rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx); rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);

View File

@ -1429,6 +1429,9 @@ class JitActivation : public Activation
RegisterBailoutIterator(JitActivation &activation, IonBailoutIterator *iter); RegisterBailoutIterator(JitActivation &activation, IonBailoutIterator *iter);
~RegisterBailoutIterator(); ~RegisterBailoutIterator();
}; };
// Return the bailout information if it is registered.
const IonBailoutIterator *bailoutData() const { return ionBailoutIterator_; }
}; };
// A filtering of the ActivationIterator to only stop at JitActivations. // A filtering of the ActivationIterator to only stop at JitActivations.