mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1062869 part 6 - Handle early execution of recover instructions. r=h4writer
This commit is contained in:
parent
153eeae0e1
commit
69ad0ca3a2
@ -444,6 +444,16 @@ class CompileInfo
|
|||||||
// would have to be executed and that they cannot be removed even if they
|
// would have to be executed and that they cannot be removed even if they
|
||||||
// are unused.
|
// are unused.
|
||||||
bool isObservableSlot(uint32_t slot) const {
|
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())
|
if (!funMaybeLazy())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -458,6 +468,13 @@ class CompileInfo
|
|||||||
if (hasArguments() && (slot == scopeChainSlot() || slot == argsObjSlot()))
|
if (hasArguments() && (slot == scopeChainSlot() || slot == argsObjSlot()))
|
||||||
return true;
|
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
|
// Function.arguments can be used to access all arguments in non-strict
|
||||||
// scripts, so we can't optimize out any arguments.
|
// scripts, so we can't optimize out any arguments.
|
||||||
if ((hasArguments() || !script()->strict()) &&
|
if ((hasArguments() || !script()->strict()) &&
|
||||||
@ -469,6 +486,19 @@ class CompileInfo
|
|||||||
return false;
|
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:
|
private:
|
||||||
unsigned nimplicit_;
|
unsigned nimplicit_;
|
||||||
unsigned nargs_;
|
unsigned nargs_;
|
||||||
|
@ -1773,6 +1773,49 @@ SnapshotIterator::skipInstruction()
|
|||||||
nextInstruction();
|
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.
|
||||||
|
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
|
bool
|
||||||
SnapshotIterator::initInstructionResults(JSContext *cx, RInstructionResults *results)
|
SnapshotIterator::initInstructionResults(JSContext *cx, RInstructionResults *results)
|
||||||
{
|
{
|
||||||
|
@ -426,6 +426,7 @@ class SnapshotIterator
|
|||||||
// recover instructions. This vector should be registered before the
|
// recover instructions. This vector should be registered before the
|
||||||
// beginning of the iteration. This function is in charge of allocating
|
// beginning of the iteration. This function is in charge of allocating
|
||||||
// enough space for all instructions results, and return false iff it fails.
|
// enough space for all instructions results, and return false iff it fails.
|
||||||
|
bool initInstructionResults(MaybeReadFallback &fallback);
|
||||||
bool initInstructionResults(JSContext *cx, RInstructionResults *results);
|
bool initInstructionResults(JSContext *cx, RInstructionResults *results);
|
||||||
|
|
||||||
void storeInstructionResult(Value v);
|
void storeInstructionResult(Value v);
|
||||||
@ -460,8 +461,16 @@ class SnapshotIterator
|
|||||||
if (allocationReadable(a))
|
if (allocationReadable(a))
|
||||||
return allocationValue(a);
|
return allocationValue(a);
|
||||||
|
|
||||||
if (fallback.canRecoverResults())
|
if (fallback.canRecoverResults()) {
|
||||||
warnUnreadableAllocation();
|
if (!initInstructionResults(fallback))
|
||||||
|
return fallback.unreadablePlaceholder;
|
||||||
|
|
||||||
|
if (allocationReadable(a))
|
||||||
|
return allocationValue(a);
|
||||||
|
|
||||||
|
MOZ_ASSERT_UNREACHABLE("All allocations should be readable.");
|
||||||
|
}
|
||||||
|
|
||||||
return fallback.unreadablePlaceholder;
|
return fallback.unreadablePlaceholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +499,7 @@ MDefinition::hasLiveDefUses() const
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(ins->isResumePoint());
|
MOZ_ASSERT(ins->isResumePoint());
|
||||||
if (ins->toResumePoint()->isObservableOperand(*i))
|
if (!ins->toResumePoint()->isRecoverableOperand(*i))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2620,6 +2620,12 @@ MResumePoint::isObservableOperand(size_t index) const
|
|||||||
return block()->info().isObservableSlot(index);
|
return block()->info().isObservableSlot(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MResumePoint::isRecoverableOperand(MUse *u) const
|
||||||
|
{
|
||||||
|
return block()->info().isRecoverableOperand(indexOf(u));
|
||||||
|
}
|
||||||
|
|
||||||
MDefinition *
|
MDefinition *
|
||||||
MToInt32::foldsTo(TempAllocator &alloc)
|
MToInt32::foldsTo(TempAllocator &alloc)
|
||||||
{
|
{
|
||||||
|
@ -10746,6 +10746,7 @@ class MResumePoint MOZ_FINAL :
|
|||||||
|
|
||||||
bool isObservableOperand(MUse *u) const;
|
bool isObservableOperand(MUse *u) const;
|
||||||
bool isObservableOperand(size_t index) const;
|
bool isObservableOperand(size_t index) const;
|
||||||
|
bool isRecoverableOperand(MUse *u) const;
|
||||||
|
|
||||||
MDefinition *getOperand(size_t index) const {
|
MDefinition *getOperand(size_t index) const {
|
||||||
return operands_[index].producer();
|
return operands_[index].producer();
|
||||||
|
@ -146,8 +146,8 @@ IsObjectEscaped(MInstruction *ins)
|
|||||||
MNode *consumer = (*i)->consumer();
|
MNode *consumer = (*i)->consumer();
|
||||||
if (!consumer->isDefinition()) {
|
if (!consumer->isDefinition()) {
|
||||||
// Cannot optimize if it is observable from fun.arguments or others.
|
// Cannot optimize if it is observable from fun.arguments or others.
|
||||||
if (consumer->toResumePoint()->isObservableOperand(*i)) {
|
if (!consumer->toResumePoint()->isRecoverableOperand(*i)) {
|
||||||
JitSpewDef(JitSpew_Escape, "Object is observable\n", ins);
|
JitSpewDef(JitSpew_Escape, "Observable object cannot be recovered\n", ins);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -525,8 +525,8 @@ IsArrayEscaped(MInstruction *ins)
|
|||||||
MNode *consumer = (*i)->consumer();
|
MNode *consumer = (*i)->consumer();
|
||||||
if (!consumer->isDefinition()) {
|
if (!consumer->isDefinition()) {
|
||||||
// Cannot optimize if it is observable from fun.arguments or others.
|
// Cannot optimize if it is observable from fun.arguments or others.
|
||||||
if (consumer->toResumePoint()->isObservableOperand(*i)) {
|
if (!consumer->toResumePoint()->isRecoverableOperand(*i)) {
|
||||||
JitSpewDef(JitSpew_Escape, "Array is observable\n", ins);
|
JitSpewDef(JitSpew_Escape, "Observable array cannot be recovered\n", ins);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
Loading…
Reference in New Issue
Block a user