зеркало из https://github.com/mozilla/gecko-dev.git
Bug 990106 part 3 - Recover RInstructions during bailouts. r=jandem
This commit is contained in:
Родитель
a0e1f8e563
Коммит
f2ea1dcb9f
|
@ -236,7 +236,7 @@ typedef enum JSWhyMagic
|
|||
JS_BLOCK_NEEDS_CLONE, /* value of static block object slot */
|
||||
JS_HASH_KEY_EMPTY, /* see class js::HashableValue */
|
||||
JS_ION_ERROR, /* error while running Ion code */
|
||||
JS_ION_BAILOUT, /* status code to signal EnterIon will OSR into Interpret */
|
||||
JS_ION_BAILOUT, /* missing recover instruction result */
|
||||
JS_OPTIMIZED_OUT, /* optimized out slot */
|
||||
JS_GENERIC_MAGIC /* for local use */
|
||||
} JSWhyMagic;
|
||||
|
|
|
@ -47,7 +47,8 @@ SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
|
|||
iter.ionScript()->recoversSize()),
|
||||
fp_(iter.jsFrame()),
|
||||
machine_(iter.machineState()),
|
||||
ionScript_(iter.ionScript())
|
||||
ionScript_(iter.ionScript()),
|
||||
instructionResults_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1336,8 +1336,12 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
|
|||
return BAILOUT_RETURN_FATAL_ERROR;
|
||||
IonSpew(IonSpew_BaselineBailouts, " Incoming frame ptr = %p", builder.startFrame());
|
||||
|
||||
AutoValueVector instructionResults(cx);
|
||||
SnapshotIterator snapIter(iter);
|
||||
|
||||
if (!snapIter.initIntructionResults(instructionResults))
|
||||
return BAILOUT_RETURN_FATAL_ERROR;
|
||||
|
||||
RootedFunction callee(cx, iter.maybeCallee());
|
||||
RootedScript scr(cx, iter.script());
|
||||
if (callee) {
|
||||
|
@ -1365,7 +1369,12 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
|
|||
jsbytecode *topCallerPC = nullptr;
|
||||
|
||||
while (true) {
|
||||
MOZ_ASSERT(snapIter.instruction()->isResumePoint());
|
||||
if (!snapIter.instruction()->isResumePoint()) {
|
||||
if (!snapIter.instruction()->recover(cx, snapIter))
|
||||
return BAILOUT_RETURN_FATAL_ERROR;
|
||||
snapIter.nextInstruction();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (frameNo > 0) {
|
||||
TraceLogStartEvent(logger, TraceLogCreateTextId(logger, scr));
|
||||
|
|
|
@ -1338,7 +1338,8 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot
|
|||
ionScript->recoversSize()),
|
||||
fp_(fp),
|
||||
machine_(machine),
|
||||
ionScript_(ionScript)
|
||||
ionScript_(ionScript),
|
||||
instructionResults_(nullptr)
|
||||
{
|
||||
JS_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
|
||||
}
|
||||
|
@ -1353,7 +1354,8 @@ SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
|
|||
iter.ionScript()->recoversSize()),
|
||||
fp_(iter.jsFrame()),
|
||||
machine_(iter.machineState()),
|
||||
ionScript_(iter.ionScript())
|
||||
ionScript_(iter.ionScript()),
|
||||
instructionResults_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1361,7 +1363,8 @@ SnapshotIterator::SnapshotIterator()
|
|||
: snapshot_(nullptr, 0, 0, 0),
|
||||
recover_(snapshot_, nullptr, 0),
|
||||
fp_(nullptr),
|
||||
ionScript_(nullptr)
|
||||
ionScript_(nullptr),
|
||||
instructionResults_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1426,6 +1429,9 @@ SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
|
|||
return hasStack(alloc.stackOffset());
|
||||
#endif
|
||||
|
||||
case RValueAllocation::RECOVER_INSTRUCTION:
|
||||
return hasInstructionResult(alloc.index());
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -1531,6 +1537,9 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
|||
}
|
||||
#endif
|
||||
|
||||
case RValueAllocation::RECOVER_INSTRUCTION:
|
||||
return fromInstructionResult(alloc.index());
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
}
|
||||
|
@ -1545,7 +1554,7 @@ SnapshotIterator::resumePoint() const
|
|||
uint32_t
|
||||
SnapshotIterator::numAllocations() const
|
||||
{
|
||||
return resumePoint()->numOperands();
|
||||
return instruction()->numOperands();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -1564,6 +1573,43 @@ SnapshotIterator::skipInstruction()
|
|||
nextInstruction();
|
||||
}
|
||||
|
||||
bool
|
||||
SnapshotIterator::initIntructionResults(AutoValueVector &results)
|
||||
{
|
||||
MOZ_ASSERT(recover_.numInstructionsRead() == 1);
|
||||
|
||||
// The last instruction will always be a resume point, no need to allocate
|
||||
// space for it.
|
||||
if (recover_.numInstructions() == 1)
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(recover_.numInstructions() > 1);
|
||||
size_t numResults = recover_.numInstructions() - 1;
|
||||
if (!results.reserve(numResults))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < numResults; i++)
|
||||
results.infallibleAppend(MagicValue(JS_ION_BAILOUT));
|
||||
|
||||
instructionResults_ = &results;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotIterator::storeInstructionResult(Value v)
|
||||
{
|
||||
uint32_t currIns = recover_.numInstructionsRead() - 1;
|
||||
MOZ_ASSERT((*instructionResults_)[currIns].isMagic(JS_ION_BAILOUT));
|
||||
(*instructionResults_)[currIns].set(v);
|
||||
}
|
||||
|
||||
Value
|
||||
SnapshotIterator::fromInstructionResult(uint32_t index) const
|
||||
{
|
||||
MOZ_ASSERT(!(*instructionResults_)[index].isMagic(JS_ION_BAILOUT));
|
||||
return (*instructionResults_)[index];
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotIterator::nextFrame()
|
||||
{
|
||||
|
|
|
@ -258,6 +258,7 @@ class SnapshotIterator
|
|||
IonJSFrameLayout *fp_;
|
||||
MachineState machine_;
|
||||
IonScript *ionScript_;
|
||||
AutoValueVector *instructionResults_;
|
||||
|
||||
private:
|
||||
// Read a spilled register from the machine state.
|
||||
|
@ -281,6 +282,11 @@ class SnapshotIterator
|
|||
}
|
||||
uintptr_t fromStack(int32_t offset) const;
|
||||
|
||||
bool hasInstructionResult(uint32_t index) const {
|
||||
return instructionResults_;
|
||||
}
|
||||
Value fromInstructionResult(uint32_t index) const;
|
||||
|
||||
Value allocationValue(const RValueAllocation &a);
|
||||
bool allocationReadable(const RValueAllocation &a);
|
||||
void warnUnreadableAllocation();
|
||||
|
@ -338,6 +344,14 @@ class SnapshotIterator
|
|||
return recover_.moreInstructions();
|
||||
}
|
||||
|
||||
// Register a vector used for storing the results of the evaluation of
|
||||
// recover instructions. This vector should be registered before the
|
||||
// beginning of the iteration. This function is in charge of allocating
|
||||
// enough space for all instructions results, and return false iff it fails.
|
||||
bool initIntructionResults(AutoValueVector &results);
|
||||
|
||||
void storeInstructionResult(Value v);
|
||||
|
||||
public:
|
||||
// Handle iterating over frames of the snapshots.
|
||||
void nextFrame();
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
|
||||
#include "jit/Recover.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "jit/IonSpewer.h"
|
||||
#include "jit/JitFrameIterator.h"
|
||||
#include "jit/MIR.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
|
||||
|
@ -25,9 +28,17 @@ RInstruction::readRecoverData(CompactBufferReader &reader, RInstructionStorage *
|
|||
{
|
||||
uint32_t op = reader.readUnsigned();
|
||||
switch (Opcode(op)) {
|
||||
case Recover_ResumePoint:
|
||||
new (raw->addr()) RResumePoint(reader);
|
||||
# define MATCH_OPCODES_(op) \
|
||||
case Recover_##op: \
|
||||
static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
|
||||
"Storage space is too small to decode R" #op " instructions."); \
|
||||
new (raw->addr()) R##op(reader); \
|
||||
break;
|
||||
|
||||
RECOVER_OPCODE_LIST(MATCH_OPCODES_)
|
||||
# undef DEFINE_OPCODES_
|
||||
|
||||
case Recover_Invalid:
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Bad decoding of the previous instruction?");
|
||||
break;
|
||||
|
@ -108,10 +119,14 @@ MResumePoint::writeRecoverData(CompactBufferWriter &writer) const
|
|||
|
||||
RResumePoint::RResumePoint(CompactBufferReader &reader)
|
||||
{
|
||||
static_assert(sizeof(*this) <= sizeof(RInstructionStorage),
|
||||
"Storage space is too small to decode this recover instruction.");
|
||||
pcOffset_ = reader.readUnsigned();
|
||||
numOperands_ = reader.readUnsigned();
|
||||
IonSpew(IonSpew_Snapshots, "Read RResumePoint (pc offset %u, nslots %u)",
|
||||
pcOffset_, numOperands_);
|
||||
}
|
||||
|
||||
bool
|
||||
RResumePoint::recover(JSContext *cx, SnapshotIterator &iter) const
|
||||
{
|
||||
MOZ_ASSUME_UNREACHABLE("This instruction is not recoverable.");
|
||||
}
|
||||
|
|
|
@ -11,44 +11,70 @@
|
|||
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
class JSContext;
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
#define RECOVER_OPCODE_LIST(_) \
|
||||
_(ResumePoint)
|
||||
|
||||
class RResumePoint;
|
||||
class SnapshotIterator;
|
||||
|
||||
class RInstruction
|
||||
{
|
||||
public:
|
||||
enum Opcode
|
||||
{
|
||||
Recover_ResumePoint = 0
|
||||
# define DEFINE_OPCODES_(op) Recover_##op,
|
||||
RECOVER_OPCODE_LIST(DEFINE_OPCODES_)
|
||||
# undef DEFINE_OPCODES_
|
||||
Recover_Invalid
|
||||
};
|
||||
|
||||
virtual Opcode opcode() const = 0;
|
||||
|
||||
// As opposed to the MIR, there is no need to add more methods as every
|
||||
// other instruction is well abstracted under the "recover" method.
|
||||
bool isResumePoint() const {
|
||||
return opcode() == Recover_ResumePoint;
|
||||
}
|
||||
inline const RResumePoint *toResumePoint() const;
|
||||
|
||||
// Number of allocations which are encoded in the Snapshot for recovering
|
||||
// the current instruction.
|
||||
virtual uint32_t numOperands() const = 0;
|
||||
|
||||
// Function used to recover the value computed by this instruction. This
|
||||
// function reads its arguments from the allocations listed on the snapshot
|
||||
// iterator and stores its returned value on the snapshot iterator too.
|
||||
virtual bool recover(JSContext *cx, SnapshotIterator &iter) const = 0;
|
||||
|
||||
// Decode an RInstruction on top of the reserved storage space, based on the
|
||||
// tag written by the writeRecoverData function of the corresponding MIR
|
||||
// instruction.
|
||||
static void readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw);
|
||||
};
|
||||
|
||||
#define RINSTRUCTION_HEADER_(op) \
|
||||
private: \
|
||||
friend class RInstruction; \
|
||||
R##op(CompactBufferReader &reader); \
|
||||
\
|
||||
public: \
|
||||
Opcode opcode() const { \
|
||||
return RInstruction::Recover_##op; \
|
||||
}
|
||||
|
||||
class RResumePoint MOZ_FINAL : public RInstruction
|
||||
{
|
||||
private:
|
||||
uint32_t pcOffset_; // Offset from script->code.
|
||||
uint32_t numOperands_; // Number of slots.
|
||||
|
||||
friend class RInstruction;
|
||||
RResumePoint(CompactBufferReader &reader);
|
||||
|
||||
public:
|
||||
virtual Opcode opcode() const {
|
||||
return Recover_ResumePoint;
|
||||
}
|
||||
RINSTRUCTION_HEADER_(ResumePoint)
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
|
@ -56,8 +82,11 @@ class RResumePoint MOZ_FINAL : public RInstruction
|
|||
virtual uint32_t numOperands() const {
|
||||
return numOperands_;
|
||||
}
|
||||
bool recover(JSContext *cx, SnapshotIterator &iter) const;
|
||||
};
|
||||
|
||||
#undef RINSTRUCTION_HEADER_
|
||||
|
||||
const RResumePoint *
|
||||
RInstruction::toResumePoint() const
|
||||
{
|
||||
|
|
|
@ -76,6 +76,9 @@ using namespace js::jit;
|
|||
// first register/stack-offset correspond to the holder of the type,
|
||||
// and the second correspond to the payload of the JS Value.
|
||||
//
|
||||
// RECOVER_INSTRUCTION [INDEX]
|
||||
// Index into the list of recovered instruction results.
|
||||
//
|
||||
// TYPED_REG [PACKED_TAG, GPR_REG]:
|
||||
// Value with statically known type, which payload is stored in a
|
||||
// register.
|
||||
|
@ -219,6 +222,15 @@ RValueAllocation::layoutFromMode(Mode mode)
|
|||
return layout;
|
||||
}
|
||||
#endif
|
||||
case RECOVER_INSTRUCTION: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_INDEX,
|
||||
PAYLOAD_NONE,
|
||||
"instruction"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
|
||||
default: {
|
||||
static const RValueAllocation::Layout regLayout = {
|
||||
PAYLOAD_PACKED_TAG,
|
||||
|
|
|
@ -54,6 +54,8 @@ class RValueAllocation
|
|||
UNTYPED_REG = 0x06,
|
||||
UNTYPED_STACK = 0x07,
|
||||
#endif
|
||||
RECOVER_INSTRUCTION = 0x0a,
|
||||
|
||||
// The JSValueType is packed in the Mode.
|
||||
TYPED_REG_MIN = 0x10,
|
||||
TYPED_REG_MAX = 0x17,
|
||||
|
@ -236,6 +238,11 @@ class RValueAllocation
|
|||
return RValueAllocation(CONSTANT, payloadOfIndex(index));
|
||||
}
|
||||
|
||||
// Recover instruction's index
|
||||
static RValueAllocation RecoverInstruction(uint32_t index) {
|
||||
return RValueAllocation(RECOVER_INSTRUCTION, payloadOfIndex(index));
|
||||
}
|
||||
|
||||
void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
|
||||
public:
|
||||
static RValueAllocation read(CompactBufferReader &reader);
|
||||
|
@ -473,6 +480,13 @@ class RecoverReader
|
|||
public:
|
||||
RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
|
||||
|
||||
uint32_t numInstructions() const {
|
||||
return numInstructions_;
|
||||
}
|
||||
uint32_t numInstructionsRead() const {
|
||||
return numInstructionsRead_;
|
||||
}
|
||||
|
||||
bool moreInstructions() const {
|
||||
return numInstructionsRead_ < numInstructions_;
|
||||
}
|
||||
|
|
|
@ -143,13 +143,31 @@ CodeGeneratorShared::encodeAllocation(LSnapshot *snapshot, MDefinition *mir,
|
|||
if (mir->isBox())
|
||||
mir = mir->toBox()->getOperand(0);
|
||||
|
||||
MIRType type = mir->isUnused()
|
||||
? MIRType_MagicOptimizedOut
|
||||
: mir->type();
|
||||
MIRType type =
|
||||
mir->isRecoveredOnBailout() ? MIRType_None :
|
||||
mir->isUnused() ? MIRType_MagicOptimizedOut :
|
||||
mir->type();
|
||||
|
||||
RValueAllocation alloc;
|
||||
|
||||
switch (type) {
|
||||
case MIRType_None:
|
||||
{
|
||||
MOZ_ASSERT(mir->isRecoveredOnBailout());
|
||||
uint32_t index = 0;
|
||||
LRecoverInfo *recoverInfo = snapshot->recoverInfo();
|
||||
MNode **it = recoverInfo->begin(), **end = recoverInfo->end();
|
||||
while (it != end && mir != *it) {
|
||||
++it;
|
||||
++index;
|
||||
}
|
||||
|
||||
// This MDefinition is recovered, thus it should be listed in the
|
||||
// LRecoverInfo.
|
||||
MOZ_ASSERT(it != end && mir == *it);
|
||||
alloc = RValueAllocation::RecoverInstruction(index);
|
||||
break;
|
||||
}
|
||||
case MIRType_Undefined:
|
||||
alloc = RValueAllocation::Undefined();
|
||||
break;
|
||||
|
|
Загрузка…
Ссылка в новой задаче