зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1062869 part 6 - Handle early execution of recover instructions. r=h4writer
This commit is contained in:
Родитель
5fc4f04592
Коммит
9717825470
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче