Bug 988958 - Extract the frame encoding/decoding logic from Snapshots. r=h4writer

This commit is contained in:
Nicolas B. Pierron 2014-03-31 09:39:45 -07:00
parent 7bd8fdcd55
commit f83d83e539
9 changed files with 146 additions and 53 deletions

View File

@ -41,7 +41,9 @@ SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
iter.snapshotOffset(),
iter.ionScript()->snapshotsRVATableSize(),
iter.ionScript()->snapshotsListSize()),
recover_(snapshot_),
recover_(snapshot_,
iter.ionScript()->recovers(),
iter.ionScript()->recoversSize()),
fp_(iter.jsFrame()),
machine_(iter.machineState()),
ionScript_(iter.ionScript())

View File

@ -6110,6 +6110,7 @@ CodeGenerator::generateAsmJS()
// every step in CodeGenerator::link must be a nop, as asserted here:
JS_ASSERT(snapshots_.listSize() == 0);
JS_ASSERT(snapshots_.RVATableSize() == 0);
JS_ASSERT(recovers_.size() == 0);
JS_ASSERT(bailouts_.empty());
JS_ASSERT(graph.numConstants() == 0);
JS_ASSERT(safepointIndices_.empty());
@ -6233,7 +6234,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
IonScript::New(cx, recompileInfo,
graph.totalSlotCount(), scriptFrameSize,
snapshots_.listSize(), snapshots_.RVATableSize(),
bailouts_.length(), graph.numConstants(),
recovers_.size(), bailouts_.length(), graph.numConstants(),
safepointIndices_.length(), osiIndices_.length(),
cacheList_.length(), runtimeData_.length(),
safepoints_.size(), callTargets.length(),
@ -6343,6 +6344,9 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
ionScript->copyOsiIndices(&osiIndices_[0], masm);
if (snapshots_.listSize())
ionScript->copySnapshots(&snapshots_);
MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
if (recovers_.size())
ionScript->copyRecovers(&recovers_);
if (graph.numConstants())
ionScript->copyConstants(graph.constantPool());
if (callTargets.length() > 0)

View File

@ -820,9 +820,11 @@ IonScript *
IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
uint32_t frameSlots, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
size_t bailoutEntries, size_t constants, size_t safepointIndices,
size_t osiIndices, size_t cacheEntries, size_t runtimeSize,
size_t safepointsSize, size_t callTargetEntries, size_t backedgeEntries,
size_t recoversSize, size_t bailoutEntries,
size_t constants, size_t safepointIndices,
size_t osiIndices, size_t cacheEntries,
size_t runtimeSize, size_t safepointsSize,
size_t callTargetEntries, size_t backedgeEntries,
OptimizationLevel optimizationLevel)
{
static const int DataAlignment = sizeof(void *);
@ -838,6 +840,7 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
// *somewhere* and if their total overflowed there would be no memory left
// at all.
size_t paddedSnapshotsSize = AlignBytes(snapshotsListSize + snapshotsRVATableSize, DataAlignment);
size_t paddedRecoversSize = AlignBytes(recoversSize, DataAlignment);
size_t paddedBailoutSize = AlignBytes(bailoutEntries * sizeof(uint32_t), DataAlignment);
size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
@ -848,6 +851,7 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
size_t paddedCallTargetSize = AlignBytes(callTargetEntries * sizeof(JSScript *), DataAlignment);
size_t paddedBackedgeSize = AlignBytes(backedgeEntries * sizeof(PatchableBackedge), DataAlignment);
size_t bytes = paddedSnapshotsSize +
paddedRecoversSize +
paddedBailoutSize +
paddedConstantsSize +
paddedSafepointIndicesSize+
@ -895,6 +899,10 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
script->snapshotsRVATableSize_ = snapshotsRVATableSize;
offsetCursor += paddedSnapshotsSize;
script->recovers_ = offsetCursor;
script->recoversSize_ = recoversSize;
offsetCursor += paddedRecoversSize;
script->constantTable_ = offsetCursor;
script->constantEntries_ = constants;
offsetCursor += paddedConstantsSize;
@ -961,6 +969,13 @@ IonScript::copySnapshots(const SnapshotWriter *writer)
writer->RVATableBuffer(), snapshotsRVATableSize_);
}
void
IonScript::copyRecovers(const RecoverWriter *writer)
{
MOZ_ASSERT(writer->size() == recoversSize_);
memcpy((uint8_t *)this + recovers_, writer->buffer(), recoversSize_);
}
void
IonScript::copySafepoints(const SafepointWriter *writer)
{

View File

@ -143,6 +143,7 @@ class JitCode : public gc::BarrieredCell<JitCode>
};
class SnapshotWriter;
class RecoverWriter;
class SafepointWriter;
class SafepointIndex;
class OsiIndex;
@ -250,6 +251,10 @@ struct IonScript
uint32_t snapshotsListSize_;
uint32_t snapshotsRVATableSize_;
// List of instructions needed to recover stack frames.
uint32_t recovers_;
uint32_t recoversSize_;
// Constant table for constants stored in snapshots.
uint32_t constantTable_;
uint32_t constantEntries_;
@ -351,9 +356,10 @@ struct IonScript
static IonScript *New(JSContext *cx, types::RecompileInfo recompileInfo,
uint32_t frameLocals, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
size_t bailoutEntries, size_t constants,
size_t safepointIndexEntries, size_t osiIndexEntries,
size_t cacheEntries, size_t runtimeSize, size_t safepointsSize,
size_t recoversSize, size_t bailoutEntries,
size_t constants, size_t safepointIndexEntries,
size_t osiIndexEntries, size_t cacheEntries,
size_t runtimeSize, size_t safepointsSize,
size_t callTargetEntries, size_t backedgeEntries,
OptimizationLevel optimizationLevel);
static void Trace(JSTracer *trc, IonScript *script);
@ -472,6 +478,12 @@ struct IonScript
size_t snapshotsRVATableSize() const {
return snapshotsRVATableSize_;
}
const uint8_t *recovers() const {
return reinterpret_cast<const uint8_t *>(this) + recovers_;
}
size_t recoversSize() const {
return recoversSize_;
}
const uint8_t *safepoints() const {
return reinterpret_cast<const uint8_t *>(this) + safepointsStart_;
}
@ -532,6 +544,7 @@ struct IonScript
void destroyCaches();
void unlinkFromRuntime(FreeOp *fop);
void copySnapshots(const SnapshotWriter *writer);
void copyRecovers(const RecoverWriter *writer);
void copyBailoutTable(const SnapshotOffset *table);
void copyConstants(const Value *vp);
void copySafepointIndices(const SafepointIndex *firstSafepointIndex, MacroAssembler &masm);

View File

@ -309,7 +309,7 @@ class SnapshotIterator
// the call.
if (moreFrames())
return false;
return snapshot_.resumeAfter();
return recover_.resumeAfter();
}
inline BailoutKind bailoutKind() const {
return snapshot_.bailoutKind();

View File

@ -1295,7 +1295,9 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot
snapshotOffset,
ionScript->snapshotsRVATableSize(),
ionScript->snapshotsListSize()),
recover_(snapshot_),
recover_(snapshot_,
ionScript->recovers(),
ionScript->recoversSize()),
fp_(fp),
machine_(machine),
ionScript_(ionScript)
@ -1308,7 +1310,9 @@ SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter)
iter.osiIndex()->snapshotOffset(),
iter.ionScript()->snapshotsRVATableSize(),
iter.ionScript()->snapshotsListSize()),
recover_(snapshot_),
recover_(snapshot_,
iter.ionScript()->recovers(),
iter.ionScript()->recoversSize()),
fp_(iter.jsFrame()),
machine_(iter.machineState()),
ionScript_(iter.ionScript())
@ -1317,7 +1321,7 @@ SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter)
SnapshotIterator::SnapshotIterator()
: snapshot_(nullptr, 0, 0, 0),
recover_(snapshot_),
recover_(snapshot_, nullptr, 0),
fp_(nullptr),
ionScript_(nullptr)
{

View File

@ -465,19 +465,25 @@ SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset,
}
#define COMPUTE_SHIFT_AFTER_(name) (name ## _BITS + name ##_SHIFT)
#define COMPUTE_MASK_(name) (((1 << name ## _BITS) - 1) << name ##_SHIFT)
#define COMPUTE_MASK_(name) ((uint32_t(1 << name ## _BITS) - 1) << name ##_SHIFT)
// Details of snapshot header packing.
static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 3;
static const uint32_t SNAPSHOT_BAILOUTKIND_MASK = COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_RESUMEAFTER_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_RESUMEAFTER_BITS = 1;
static const uint32_t SNAPSHOT_RESUMEAFTER_MASK = COMPUTE_MASK_(SNAPSHOT_RESUMEAFTER);
static const uint32_t SNAPSHOT_ROFFSET_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);
static const uint32_t SNAPSHOT_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_RESUMEAFTER);
static const uint32_t SNAPSHOT_FRAMECOUNT_BITS = 32 - 4;
static const uint32_t SNAPSHOT_FRAMECOUNT_MASK = COMPUTE_MASK_(SNAPSHOT_FRAMECOUNT);
// Details of recover header packing.
static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
static const uint32_t RECOVER_RESUMEAFTER_MASK = COMPUTE_MASK_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_FRAMECOUNT_BITS = 32 - RECOVER_FRAMECOUNT_SHIFT;
static const uint32_t RECOVER_FRAMECOUNT_MASK = COMPUTE_MASK_(RECOVER_FRAMECOUNT);
#undef COMPUTE_MASK_
#undef COMPUTE_SHIFT_AFTER_
@ -486,24 +492,29 @@ void
SnapshotReader::readSnapshotHeader()
{
uint32_t bits = reader_.readUnsigned();
frameCount_ = bits >> SNAPSHOT_FRAMECOUNT_SHIFT;
JS_ASSERT(frameCount_ > 0);
bailoutKind_ = BailoutKind((bits & SNAPSHOT_BAILOUTKIND_MASK) >> SNAPSHOT_BAILOUTKIND_SHIFT);
resumeAfter_ = !!(bits & (1 << SNAPSHOT_RESUMEAFTER_SHIFT));
recoverOffset_ = (bits & SNAPSHOT_ROFFSET_MASK) >> SNAPSHOT_ROFFSET_SHIFT;
IonSpew(IonSpew_Snapshots, "Read snapshot header with bailout kind %u",
bailoutKind_);
#ifdef TRACK_SNAPSHOTS
readTrackSnapshot();
#endif
}
#ifdef TRACK_SNAPSHOTS
void
SnapshotReader::readTrackSnapshot()
{
pcOpcode_ = reader_.readUnsigned();
mirOpcode_ = reader_.readUnsigned();
mirId_ = reader_.readUnsigned();
lirOpcode_ = reader_.readUnsigned();
lirId_ = reader_.readUnsigned();
#endif
IonSpew(IonSpew_Snapshots, "Read snapshot header with frameCount %u, bailout kind %u (ra: %d)",
frameCount_, bailoutKind_, resumeAfter_);
}
#ifdef TRACK_SNAPSHOTS
void
SnapshotReader::spewBailingFrom() const
{
@ -539,25 +550,40 @@ SnapshotWriter::init()
return allocMap_.init(32);
}
RecoverReader::RecoverReader(SnapshotReader &snapshot)
: frameCount_(0),
RecoverReader::RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size)
: reader_(nullptr, nullptr),
frameCount_(0),
framesRead_(0),
allocCount_(0)
{
if (!snapshot.reader_.more())
if (!recovers)
return;
frameCount_ = snapshot.frameCount_;
reader_ = CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
readRecoverHeader();
readFrame(snapshot);
}
void
RecoverReader::readRecoverHeader()
{
uint32_t bits = reader_.readUnsigned();
frameCount_ = (bits & RECOVER_FRAMECOUNT_MASK) >> RECOVER_FRAMECOUNT_SHIFT;
resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
JS_ASSERT(frameCount_);
IonSpew(IonSpew_Snapshots, "Read recover header with frameCount %u (ra: %d)",
frameCount_, resumeAfter_);
}
void
RecoverReader::readFrame(SnapshotReader &snapshot)
{
JS_ASSERT(moreFrames());
JS_ASSERT(snapshot.allocRead_ == allocCount_);
pcOffset_ = snapshot.reader_.readUnsigned();
allocCount_ = snapshot.reader_.readUnsigned();
pcOffset_ = reader_.readUnsigned();
allocCount_ = reader_.readUnsigned();
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
framesRead_++;
@ -565,20 +591,15 @@ RecoverReader::readFrame(SnapshotReader &snapshot)
}
SnapshotOffset
SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter)
SnapshotWriter::startSnapshot(RecoverOffset recoverOffset, BailoutKind kind)
{
lastStart_ = writer_.length();
IonSpew(IonSpew_Snapshots, "starting snapshot with frameCount %u, bailout kind %u",
frameCount, kind);
JS_ASSERT(frameCount > 0);
JS_ASSERT(frameCount < (1 << SNAPSHOT_FRAMECOUNT_BITS));
JS_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS));
uint32_t bits = (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
(frameCount << SNAPSHOT_FRAMECOUNT_SHIFT);
if (resumeAfter)
bits |= (1 << SNAPSHOT_RESUMEAFTER_SHIFT);
JS_ASSERT(recoverOffset < (1 << SNAPSHOT_ROFFSET_BITS));
uint32_t bits =
(uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
(recoverOffset << SNAPSHOT_ROFFSET_SHIFT);
writer_.writeUnsigned(bits);
return lastStart_;
@ -648,7 +669,20 @@ RecoverWriter::startRecover(uint32_t frameCount, BailoutKind kind, bool resumeAf
MOZ_ASSERT(frameCount);
nframes_ = frameCount;
framesWritten_ = 0;
return snapshot_.startSnapshot(frameCount, kind, resumeAfter);
IonSpew(IonSpew_Snapshots, "starting snapshot with frameCount %u, bailout kind %u",
frameCount, kind);
MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_FRAMECOUNT_BITS));
uint32_t bits =
(uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
(frameCount << RECOVER_FRAMECOUNT_SHIFT);
RecoverOffset recoverOffset = writer_.length();
SnapshotOffset snapshotOffset = snapshot_.startSnapshot(recoverOffset, kind);
writer_.writeUnsigned(bits);
return snapshotOffset;
}
void
@ -671,8 +705,8 @@ RecoverWriter::startFrame(JSFunction *fun, JSScript *script,
uint32_t pcoff = script->pcToOffset(pc);
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_);
snapshot_.writer_.writeUnsigned(pcoff);
snapshot_.writer_.writeUnsigned(nallocs_);
writer_.writeUnsigned(pcoff);
writer_.writeUnsigned(nallocs_);
}
void

View File

@ -302,6 +302,8 @@ class RValueAllocation
};
};
typedef uint32_t RecoverOffset;
class RecoverWriter;
// Collects snapshots in a contiguous buffer, which is copied into IonScript
@ -327,7 +329,7 @@ class SnapshotWriter
public:
bool init();
SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
SnapshotOffset startSnapshot(RecoverOffset recoverOffset, BailoutKind kind);
#ifdef TRACK_SNAPSHOTS
void trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
uint32_t lirOpcode, uint32_t lirId);
@ -358,6 +360,7 @@ class SnapshotWriter
class RecoverWriter
{
CompactBufferWriter writer_;
SnapshotWriter &snapshot_;
uint32_t nallocs_;
@ -374,6 +377,17 @@ class RecoverWriter
void endFrame();
void endRecover();
size_t size() const {
return writer_.length();
}
const uint8_t *buffer() const {
return writer_.buffer();
}
bool oom() const {
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
}
};
class RecoverReader;
@ -390,10 +404,9 @@ class SnapshotReader
CompactBufferReader allocReader_;
const uint8_t* allocTable_;
uint32_t frameCount_;
BailoutKind bailoutKind_;
uint32_t allocRead_; // Number of slots that have been read.
bool resumeAfter_;
RecoverOffset recoverOffset_; // Offset of the recover instructions.
#ifdef TRACK_SNAPSHOTS
private:
@ -404,6 +417,7 @@ class SnapshotReader
uint32_t lirId_;
public:
void readTrackSnapshot();
void spewBailingFrom() const;
#endif
@ -420,23 +434,27 @@ class SnapshotReader
BailoutKind bailoutKind() const {
return bailoutKind_;
}
bool resumeAfter() const {
return resumeAfter_;
RecoverOffset recoverOffset() const {
return recoverOffset_;
}
};
class RecoverReader
{
CompactBufferReader reader_;
uint32_t frameCount_;
uint32_t framesRead_; // Number of frame headers that have been read.
uint32_t pcOffset_; // Offset from script->code.
uint32_t allocCount_; // Number of slots.
bool resumeAfter_;
private:
void readRecoverHeader();
void readFrame(SnapshotReader &snapshot);
public:
RecoverReader(SnapshotReader &snapshot);
RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
bool moreFrames() const {
return framesRead_ < frameCount_;
@ -451,6 +469,9 @@ class RecoverReader
uint32_t pcOffset() const {
return pcOffset_;
}
bool resumeAfter() const {
return resumeAfter_;
}
uint32_t allocations() const {
return allocCount_;

View File

@ -335,7 +335,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
recovers_.endRecover();
snapshot->setSnapshotOffset(offset);
return !snapshots_.oom();
return !recovers_.oom() || !snapshots_.oom();
}
bool