From ca52532afcb3917c7e5f1f6a3e49ec1e7adeb395 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 9 Dec 2014 22:00:44 -0500 Subject: [PATCH] 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 --- js/src/jit/IonBuilder.cpp | 104 ++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index ac02064febc2..caef02232f43 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -3367,6 +3367,11 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test) if (!ins) 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()) { case MDefinition::Op_Not: return improveTypesAtTest(ins->toNot()->getOperand(0), !trueBranch, test); @@ -3390,8 +3395,10 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test) } case MDefinition::Op_Phi: { bool branchIsAnd = true; - if (!detectAndOrStructure(ins->toPhi(), &branchIsAnd)) - return true; + if (!detectAndOrStructure(ins->toPhi(), &branchIsAnd)) { + // 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. if (branchIsAnd) { @@ -3430,53 +3437,54 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test) case MDefinition::Op_Compare: return improveTypesAtCompare(ins->toCompare(), trueBranch, test); - // 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. - 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(nullptr)); - type = types::TypeSet::intersectSets(&base, oldType, alloc_->lifoAlloc()); - } - replaceTypeSet(ins, type, test); - } - + default: + break; } - 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(nullptr)); + type = types::TypeSet::intersectSets(&base, oldType, alloc_->lifoAlloc()); + } + + return replaceTypeSet(ins, type, test); } bool