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;
case JitFrame_BaselineJS:
case JitFrame_IonJS:
case JitFrame_Bailout:
{
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)",
frameno, type, it.fp(), it.script()->filename(), it.script()->lineno(),
it.maybeCallee(), (JSScript *)it.script(), it.returnAddressToFp());

View File

@ -102,6 +102,10 @@ JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx)
cachedSafepointIndex_(nullptr),
activation_(cx->perThreadData->activation()->asJit())
{
if (activation_->bailoutData()) {
current_ = activation_->bailoutData()->fp();
type_ = JitFrame_Bailout;
}
}
JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
@ -115,6 +119,10 @@ JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
cachedSafepointIndex_(nullptr),
activation_(activations->asJit())
{
if (activation_->bailoutData()) {
current_ = activation_->bailoutData()->fp();
type_ = JitFrame_Bailout;
}
}
IonBailoutIterator *
@ -275,6 +283,7 @@ SizeOfFramePrefix(FrameType type)
return IonEntryFrameLayout::Size();
case JitFrame_BaselineJS:
case JitFrame_IonJS:
case JitFrame_Bailout:
case JitFrame_Unwound_IonJS:
return IonJSFrameLayout::Size();
case JitFrame_BaselineStub:
@ -339,6 +348,8 @@ JitFrameIterator::operator++()
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,
@ -349,6 +360,12 @@ JitFrameIterator::spillBase() const
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();
@ -1532,7 +1549,7 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot
SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
: snapshot_(iter.ionScript()->snapshots(),
iter.osiIndex()->snapshotOffset(),
iter.snapshotOffset(),
iter.ionScript()->snapshotsRVATableSize(),
iter.ionScript()->snapshotsListSize()),
recover_(snapshot_,
@ -1916,10 +1933,22 @@ SnapshotIterator::maybeReadAllocByIndex(size_t index)
return s;
}
IonJSFrameLayout *
JitFrameIterator::jsFrame() const
{
MOZ_ASSERT(isScripted());
if (isBailoutJS())
return activation_->bailoutData()->jsFrame();
return (IonJSFrameLayout *) fp();
}
IonScript *
JitFrameIterator::ionScript() const
{
MOZ_ASSERT(type() == JitFrame_IonJS);
MOZ_ASSERT(isIonScripted());
if (isBailoutJS())
return activation_->bailoutData()->ionScript();
IonScript *ionScript = nullptr;
if (checkInvalidation(&ionScript))
@ -1930,7 +1959,7 @@ JitFrameIterator::ionScript() const
IonScript *
JitFrameIterator::ionScriptFromCalleeToken() const
{
MOZ_ASSERT(type() == JitFrame_IonJS);
MOZ_ASSERT(isIonJS());
MOZ_ASSERT(!checkInvalidation());
switch (mode_) {
@ -1946,14 +1975,25 @@ JitFrameIterator::ionScriptFromCalleeToken() const
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());
}
@ -2335,6 +2375,7 @@ JitFrameIterator::dump() const
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);

View File

@ -57,7 +57,13 @@ enum FrameType
// 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
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 {
@ -127,10 +133,9 @@ class JitFrameIterator
inline uint8_t *returnAddress() const;
IonJSFrameLayout *jsFrame() const {
MOZ_ASSERT(isScripted());
return (IonJSFrameLayout *) fp();
}
// Return the pointer of the JitFrame, the iterator is assumed to be settled
// on a scripted frame.
IonJSFrameLayout *jsFrame() const;
// Returns true iff this exit frame was created using EnsureExitFrame.
inline bool isFakeExitFrame() const;
@ -143,14 +148,20 @@ class JitFrameIterator
bool checkInvalidation() const;
bool isScripted() const {
return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS;
return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
}
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;
}
@ -216,6 +227,10 @@ class JitFrameIterator
// 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;

View File

@ -351,6 +351,15 @@ FrameIter::unaliasedForEachActual(JSContext *cx, Op op)
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);

View File

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

View File

@ -1429,6 +1429,9 @@ class JitActivation : public Activation
RegisterBailoutIterator(JitActivation &activation, IonBailoutIterator *iter);
~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.