Bug 1004388 part 1. When we're testing an MPhi that doesn't represent the and-or pattern, just fall back to optimizing the typeset for the true/false branches based on the truthiness directly, like we would for the non-MPhi case. r=jandem

This commit is contained in:
Boris Zbarsky 2014-12-09 22:00:44 -05:00
Родитель 9284760710
Коммит ca52532afc
1 изменённых файлов: 56 добавлений и 48 удалений

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

@ -3367,6 +3367,11 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test)
if (!ins) if (!ins)
return true; return true;
// All branches of this switch that don't want to fall through to the
// default behavior must return. The default behavior assumes that a true
// test means the incoming ins is not null or undefined and that a false
// tests means it's one of null, undefined, false, 0, "", and objects
// emulating undefined
switch (ins->op()) { switch (ins->op()) {
case MDefinition::Op_Not: case MDefinition::Op_Not:
return improveTypesAtTest(ins->toNot()->getOperand(0), !trueBranch, test); return improveTypesAtTest(ins->toNot()->getOperand(0), !trueBranch, test);
@ -3390,8 +3395,10 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test)
} }
case MDefinition::Op_Phi: { case MDefinition::Op_Phi: {
bool branchIsAnd = true; bool branchIsAnd = true;
if (!detectAndOrStructure(ins->toPhi(), &branchIsAnd)) if (!detectAndOrStructure(ins->toPhi(), &branchIsAnd)) {
return true; // Just fall through to the default behavior.
break;
}
// Now we have detected the triangular structure and determined if it was an AND or an OR. // Now we have detected the triangular structure and determined if it was an AND or an OR.
if (branchIsAnd) { if (branchIsAnd) {
@ -3430,53 +3437,54 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test)
case MDefinition::Op_Compare: case MDefinition::Op_Compare:
return improveTypesAtCompare(ins->toCompare(), trueBranch, test); return improveTypesAtCompare(ins->toCompare(), trueBranch, test);
// By default MTest tests ToBoolean(input). As a result in the true branch we can filter default:
// undefined and null. In false branch we can only encounter undefined, null, false, 0, "" break;
// and objects that emulate undefined.
default: {
// If ins does not have a typeset we return as we cannot optimize.
if (!ins->resultTypeSet() || ins->resultTypeSet()->unknown())
return true;
types::TemporaryTypeSet *oldType = ins->resultTypeSet();
types::TemporaryTypeSet *type;
// Decide either to set or filter.
if (trueBranch) {
// Filter undefined/null.
if (!ins->mightBeType(MIRType_Undefined) &&
!ins->mightBeType(MIRType_Null))
{
return true;
}
type = oldType->filter(alloc_->lifoAlloc(), true, true);
} else {
// According to the standards, we cannot filter out: Strings,
// Int32, Double, Booleans, Objects (if they emulate undefined)
uint32_t flags = types::TYPE_FLAG_PRIMITIVE;
// If the typeset does emulate undefined, then we cannot filter out
// objects.
if (oldType->maybeEmulatesUndefined())
flags |= types::TYPE_FLAG_ANYOBJECT;
// Only intersect the typesets if it will generate a more narrow
// typeset. The first part takes care of primitives and AnyObject,
// while the second line specific (type)objects.
if (!oldType->hasAnyFlag(~flags & types::TYPE_FLAG_BASE_MASK) &&
(oldType->maybeEmulatesUndefined() || !oldType->maybeObject()))
{
return true;
}
types::TemporaryTypeSet base(flags, static_cast<types::TypeObjectKey**>(nullptr));
type = types::TypeSet::intersectSets(&base, oldType, alloc_->lifoAlloc());
}
replaceTypeSet(ins, type, test);
}
} }
return true;
// By default MTest tests ToBoolean(input). As a result in the true branch we can filter
// undefined and null. In false branch we can only encounter undefined, null, false, 0, ""
// and objects that emulate undefined.
// If ins does not have a typeset we return as we cannot optimize.
if (!ins->resultTypeSet() || ins->resultTypeSet()->unknown())
return true;
types::TemporaryTypeSet *oldType = ins->resultTypeSet();
types::TemporaryTypeSet *type;
// Decide either to set or filter.
if (trueBranch) {
// Filter undefined/null.
if (!ins->mightBeType(MIRType_Undefined) &&
!ins->mightBeType(MIRType_Null))
{
return true;
}
type = oldType->filter(alloc_->lifoAlloc(), true, true);
} else {
// According to the standards, we cannot filter out: Strings,
// Int32, Double, Booleans, Objects (if they emulate undefined)
uint32_t flags = types::TYPE_FLAG_PRIMITIVE;
// If the typeset does emulate undefined, then we cannot filter out
// objects.
if (oldType->maybeEmulatesUndefined())
flags |= types::TYPE_FLAG_ANYOBJECT;
// Only intersect the typesets if it will generate a more narrow
// typeset. The first part takes care of primitives and AnyObject,
// while the second line specific (type)objects.
if (!oldType->hasAnyFlag(~flags & types::TYPE_FLAG_BASE_MASK) &&
(oldType->maybeEmulatesUndefined() || !oldType->maybeObject()))
{
return true;
}
types::TemporaryTypeSet base(flags, static_cast<types::TypeObjectKey**>(nullptr));
type = types::TypeSet::intersectSets(&base, oldType, alloc_->lifoAlloc());
}
return replaceTypeSet(ins, type, test);
} }
bool bool