Bug 1062869 part 6 - Handle early execution of recover instructions. r=h4writer

This commit is contained in:
Nicolas B. Pierron 2014-09-23 19:42:35 +02:00
Родитель 5fc4f04592
Коммит 9717825470
6 изменённых файлов: 97 добавлений и 7 удалений

Просмотреть файл

@ -444,6 +444,16 @@ class CompileInfo
// would have to be executed and that they cannot be removed even if they
// are unused.
bool isObservableSlot(uint32_t slot) const {
if (isObservableFrameSlot(slot))
return true;
if (isObservableArgumentSlot(slot))
return true;
return false;
}
bool isObservableFrameSlot(uint32_t slot) const {
if (!funMaybeLazy())
return false;
@ -458,6 +468,13 @@ class CompileInfo
if (hasArguments() && (slot == scopeChainSlot() || slot == argsObjSlot()))
return true;
return false;
}
bool isObservableArgumentSlot(uint32_t slot) const {
if (!funMaybeLazy())
return false;
// Function.arguments can be used to access all arguments in non-strict
// scripts, so we can't optimize out any arguments.
if ((hasArguments() || !script()->strict()) &&
@ -469,6 +486,19 @@ class CompileInfo
return false;
}
// Returns true if a slot can be recovered before or during a bailout. A
// definition which can be observed and recovered, implies that this
// definition can be optimized away as long as we can compute its values.
bool isRecoverableOperand(uint32_t slot) const {
if (isObservableFrameSlot(slot))
return false;
if (needsArgsObj() && isObservableArgumentSlot(slot))
return false;
return true;
}
private:
unsigned nimplicit_;
unsigned nargs_;

Просмотреть файл

@ -1772,6 +1772,50 @@ SnapshotIterator::skipInstruction()
nextInstruction();
}
bool
SnapshotIterator::initInstructionResults(MaybeReadFallback &fallback)
{
MOZ_ASSERT(fallback.canRecoverResults());
JSContext *cx = fallback.maybeCx;
// If there is only one resume point in the list of instructions, then there
// is no instruction to recover, and thus no need to register any results.
MOZ_ASSERT(recover_.numInstructionsRead() == 1);
if (recover_.numInstructions() == 1)
return true;
IonJSFrameLayout *fp = fallback.frame->jsFrame();
RInstructionResults *results = fallback.activation->maybeIonFrameRecovery(fp);
if (!results) {
// We do not have the result yet, which means that an observable stack
// slot is requested. As we do not want to bailout every time for the
// same reason, we need to recompile without optimizing away the
// observable stack slots. The script would later be recompiled to have
// support for Argument objects.
if (!ionScript_->invalidate(cx, /* resetUses = */ false, "Observe recovered instruction."))
return false;
// Start a new snapshot at the beginning of the JitFrameIterator. This
// SnapshotIterator is used for evaluating the content of all recover
// instructions. The result is then saved on the JitActivation.
SnapshotIterator s(*fallback.frame);
RInstructionResults tmp;
if (!s.initInstructionResults(cx, &tmp))
return false;
// Register the list of result on the activation.
if (!fallback.activation->registerIonFrameRecovery(fallback.frame->jsFrame(),
mozilla::Move(tmp)))
return false;
results = fallback.activation->maybeIonFrameRecovery(fp);
}
MOZ_ASSERT(results->isInitialized());
instructionResults_ = results;
return true;
}
bool
SnapshotIterator::initInstructionResults(JSContext *cx, RInstructionResults *results)
{

Просмотреть файл

@ -424,6 +424,7 @@ class SnapshotIterator
// 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 initInstructionResults(MaybeReadFallback &fallback);
bool initInstructionResults(JSContext *cx, RInstructionResults *results);
void storeInstructionResult(Value v);
@ -458,8 +459,16 @@ class SnapshotIterator
if (allocationReadable(a))
return allocationValue(a);
if (fallback.canRecoverResults())
warnUnreadableAllocation();
if (fallback.canRecoverResults()) {
if (!initInstructionResults(fallback))
return fallback.unreadablePlaceholder;
if (allocationReadable(a))
return allocationValue(a);
MOZ_ASSERT_UNREACHABLE("All allocations should be readable.");
}
return fallback.unreadablePlaceholder;
}

Просмотреть файл

@ -501,7 +501,7 @@ MDefinition::hasLiveDefUses() const
return true;
} else {
MOZ_ASSERT(ins->isResumePoint());
if (ins->toResumePoint()->isObservableOperand(*i))
if (!ins->toResumePoint()->isRecoverableOperand(*i))
return true;
}
}
@ -2708,6 +2708,12 @@ MResumePoint::isObservableOperand(size_t index) const
return block()->info().isObservableSlot(index);
}
bool
MResumePoint::isRecoverableOperand(MUse *u) const
{
return block()->info().isRecoverableOperand(indexOf(u));
}
MDefinition *
MToInt32::foldsTo(TempAllocator &alloc)
{

Просмотреть файл

@ -10796,6 +10796,7 @@ class MResumePoint MOZ_FINAL :
bool isObservableOperand(MUse *u) const;
bool isObservableOperand(size_t index) const;
bool isRecoverableOperand(MUse *u) const;
MDefinition *getOperand(size_t index) const {
return operands_[index].producer();

Просмотреть файл

@ -146,8 +146,8 @@ IsObjectEscaped(MInstruction *ins)
MNode *consumer = (*i)->consumer();
if (!consumer->isDefinition()) {
// Cannot optimize if it is observable from fun.arguments or others.
if (consumer->toResumePoint()->isObservableOperand(*i)) {
JitSpewDef(JitSpew_Escape, "Object is observable\n", ins);
if (!consumer->toResumePoint()->isRecoverableOperand(*i)) {
JitSpewDef(JitSpew_Escape, "Observable object cannot be recovered\n", ins);
return true;
}
continue;
@ -525,8 +525,8 @@ IsArrayEscaped(MInstruction *ins)
MNode *consumer = (*i)->consumer();
if (!consumer->isDefinition()) {
// Cannot optimize if it is observable from fun.arguments or others.
if (consumer->toResumePoint()->isObservableOperand(*i)) {
JitSpewDef(JitSpew_Escape, "Array is observable\n", ins);
if (!consumer->toResumePoint()->isRecoverableOperand(*i)) {
JitSpewDef(JitSpew_Escape, "Observable array cannot be recovered\n", ins);
return true;
}
continue;