Backed out changeset 3a23bcbc4e60 (bug 953164) for JS Reftest Bustage on a CLOSED TREE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 26 Feb 2014 14:00:34 +0100
changeset 171022 b90bf66240666f255fcca4064309942db531d60c
parent 171021 20226f09d05969f56a96f06e0225dc67b4abf8af
child 171023 3a737c64fa7433212f03ed69ff18d02f007d1a83
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
bugs953164
milestone30.0a1
backs out3a23bcbc4e60663cf49d8faddf9ce27948c20669
Backed out changeset 3a23bcbc4e60 (bug 953164) for JS Reftest Bustage on a CLOSED TREE
js/src/jit/Ion.cpp
js/src/jit/IonAnalysis.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/ParallelSafetyAnalysis.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1372,18 +1372,18 @@ OptimizeMIR(MIRGenerator *mir)
 
     if (mir->optimizationInfo().eliminateRedundantChecksEnabled()) {
         // Note: check elimination has to run after all other passes that move
         // instructions. Since check uses are replaced with the actual index,
         // code motion after this pass could incorrectly move a load or store
         // before its bounds check.
         if (!EliminateRedundantChecks(graph))
             return false;
+        IonSpewPass("Bounds Check Elimination");
         AssertGraphCoherency(graph);
-        IonSpewPass("Bounds Check Elimination");
     }
 
     return true;
 }
 
 LIRGraph *
 GenerateLIR(MIRGenerator *mir)
 {
@@ -1391,17 +1391,17 @@ GenerateLIR(MIRGenerator *mir)
 
     LIRGraph *lir = mir->alloc().lifoAlloc()->new_<LIRGraph>(&graph);
     if (!lir)
         return nullptr;
 
     LIRGenerator lirgen(mir, graph, *lir);
     if (!lirgen.generate())
         return nullptr;
-    //IonSpewPass("Generate LIR");
+    IonSpewPass("Generate LIR");
 
     if (mir->shouldCancel("Generate LIR"))
         return nullptr;
 
     AllocationIntegrityState integrity(*lir);
 
     switch (mir->optimizationInfo().registerAllocator()) {
       case RegisterAllocator_LSRA: {
@@ -1414,17 +1414,17 @@ GenerateLIR(MIRGenerator *mir)
         if (!regalloc.go())
             return nullptr;
 
 #ifdef DEBUG
         if (!integrity.check(false))
             return nullptr;
 #endif
 
-        //IonSpewPass("Allocate Registers [LSRA]", &regalloc);
+        IonSpewPass("Allocate Registers [LSRA]", &regalloc);
         break;
       }
 
       case RegisterAllocator_Backtracking: {
 #ifdef DEBUG
         if (!integrity.record())
             return nullptr;
 #endif
@@ -1433,47 +1433,47 @@ GenerateLIR(MIRGenerator *mir)
         if (!regalloc.go())
             return nullptr;
 
 #ifdef DEBUG
         if (!integrity.check(false))
             return nullptr;
 #endif
 
-        //IonSpewPass("Allocate Registers [Backtracking]");
+        IonSpewPass("Allocate Registers [Backtracking]");
         break;
       }
 
       case RegisterAllocator_Stupid: {
         // Use the integrity checker to populate safepoint information, so
         // run it in all builds.
         if (!integrity.record())
             return nullptr;
 
         StupidAllocator regalloc(mir, &lirgen, *lir);
         if (!regalloc.go())
             return nullptr;
         if (!integrity.check(true))
             return nullptr;
-        //IonSpewPass("Allocate Registers [Stupid]");
+        IonSpewPass("Allocate Registers [Stupid]");
         break;
       }
 
       default:
         MOZ_ASSUME_UNREACHABLE("Bad regalloc");
     }
 
     if (mir->shouldCancel("Allocate Registers"))
         return nullptr;
 
     // Now that all optimization and register allocation is done, re-introduce
     // critical edges to avoid unnecessary jumps.
     if (!UnsplitEdges(lir))
         return nullptr;
-    //IonSpewPass("Unsplit Critical Edges");
+    IonSpewPass("Unsplit Critical Edges");
     AssertBasicGraphCoherency(graph);
 
     return lir;
 }
 
 CodeGenerator *
 GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm)
 {
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1282,32 +1282,29 @@ jit::AssertBasicGraphCoherency(MIRGraph 
         JS_ASSERT(!osrBlock->unreachable());
     }
 
     if (MResumePoint *resumePoint = graph.entryResumePoint())
         JS_ASSERT(resumePoint->block() == graph.entryBlock());
 
     // Assert successor and predecessor list coherency.
     uint32_t count = 0;
-    size_t compares = 0;
     for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
         count++;
 
         JS_ASSERT(&block->graph() == &graph);
 
         for (size_t i = 0; i < block->numSuccessors(); i++)
             JS_ASSERT(CheckSuccessorImpliesPredecessor(*block, block->getSuccessor(i)));
 
         for (size_t i = 0; i < block->numPredecessors(); i++)
             JS_ASSERT(CheckPredecessorImpliesSuccessor(*block, block->getPredecessor(i)));
 
         // Assert that use chains are valid for this instruction.
         for (MDefinitionIterator iter(*block); iter; iter++) {
-            if (iter->isCompare())
-                compares++;
             for (uint32_t i = 0, e = iter->numOperands(); i < e; i++)
                 JS_ASSERT(CheckOperandImpliesUse(*iter, iter->getOperand(i)));
         }
         for (MResumePointIterator iter(block->resumePointsBegin()); iter != block->resumePointsEnd(); iter++) {
             for (uint32_t i = 0, e = iter->numOperands(); i < e; i++) {
                 if (iter->getUseFor(i)->hasProducer())
                     JS_ASSERT(CheckOperandImpliesUse(*iter, iter->getOperand(i)));
             }
@@ -1645,41 +1642,52 @@ TryEliminateTypeBarrierFromTest(MTypeBar
     // Disregard the possible unbox added before the Typebarrier for checking.
     MDefinition *input = barrier->input();
     MUnbox *inputUnbox = nullptr;
     if (input->isUnbox() && input->toUnbox()->mode() != MUnbox::Fallible) {
         inputUnbox = input->toUnbox();
         input = inputUnbox->input();
     }
 
-    MDefinition *subject = nullptr;
-    bool removeUndefined;
-    bool removeNull;
-    test->filtersUndefinedOrNull(direction == TRUE_BRANCH, &subject, &removeUndefined, &removeNull);
+    if (test->getOperand(0) == input && direction == TRUE_BRANCH) {
+        *eliminated = true;
+        if (inputUnbox)
+            inputUnbox->makeInfallible();
+        barrier->replaceAllUsesWith(barrier->input());
+        return;
+    }
 
-    // The Test doesn't filter undefined nor null.
-    if (!subject)
-        return;
-
-    // Make sure the subject equals the input to the TypeBarrier.
-    if (subject != input)
+    if (!test->getOperand(0)->isCompare())
         return;
 
-    // When the TypeBarrier filters undefined, the test must at least also do,
-    // this, before the TypeBarrier can get removed.
-    if (!removeUndefined && filtersUndefined)
+    MCompare *compare = test->getOperand(0)->toCompare();
+    MCompare::CompareType compareType = compare->compareType();
+
+    if (compareType != MCompare::Compare_Undefined && compareType != MCompare::Compare_Null)
+        return;
+    if (compare->getOperand(0) != input)
         return;
 
-    // When the TypeBarrier filters null, the test must at least also do,
-    // this, before the TypeBarrier can get removed.
-    if (!removeNull && filtersNull)
+    JSOp op = compare->jsop();
+    JS_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ ||
+              op == JSOP_NE || op == JSOP_STRICTNE);
+
+    if ((direction == TRUE_BRANCH) != (op == JSOP_NE || op == JSOP_STRICTNE))
         return;
 
-    // Eliminate the TypeBarrier. The possible TypeBarrier unboxing is kept,
-    // but made infallible.
+    // A test 'if (x.f != null)' or 'if (x.f != undefined)' filters both null
+    // and undefined. If strict equality is used, only the specified rhs is
+    // tested for.
+    if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE) {
+        if (compareType == MCompare::Compare_Undefined && !filtersUndefined)
+            return;
+        if (compareType == MCompare::Compare_Null && !filtersNull)
+            return;
+    }
+
     *eliminated = true;
     if (inputUnbox)
         inputUnbox->makeInfallible();
     barrier->replaceAllUsesWith(barrier->input());
 }
 
 static bool
 TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -184,55 +184,50 @@ IonBuilder::spew(const char *message)
 static inline int32_t
 GetJumpOffset(jsbytecode *pc)
 {
     JS_ASSERT(js_CodeSpec[JSOp(*pc)].type() == JOF_JUMP);
     return GET_JUMP_OFFSET(pc);
 }
 
 IonBuilder::CFGState
-IonBuilder::CFGState::If(jsbytecode *join, MTest *test)
+IonBuilder::CFGState::If(jsbytecode *join, MBasicBlock *ifFalse)
 {
     CFGState state;
     state.state = IF_TRUE;
     state.stopAt = join;
-    state.branch.ifFalse = test->ifFalse();
-    state.branch.test = test;
+    state.branch.ifFalse = ifFalse;
     return state;
 }
 
 IonBuilder::CFGState
-IonBuilder::CFGState::IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MTest *test)
-{
-    MBasicBlock *ifFalse = test->ifFalse();
-
+IonBuilder::CFGState::IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MBasicBlock *ifFalse)
+{
     CFGState state;
     // If the end of the false path is the same as the start of the
     // false path, then the "else" block is empty and we can devolve
     // this to the IF_TRUE case. We handle this here because there is
     // still an extra GOTO on the true path and we want stopAt to point
     // there, whereas the IF_TRUE case does not have the GOTO.
     state.state = (falseEnd == ifFalse->pc())
                   ? IF_TRUE_EMPTY_ELSE
                   : IF_ELSE_TRUE;
     state.stopAt = trueEnd;
     state.branch.falseEnd = falseEnd;
     state.branch.ifFalse = ifFalse;
-    state.branch.test = test;
     return state;
 }
 
 IonBuilder::CFGState
 IonBuilder::CFGState::AndOr(jsbytecode *join, MBasicBlock *joinStart)
 {
     CFGState state;
     state.state = AND_OR;
     state.stopAt = join;
     state.branch.ifFalse = joinStart;
-    state.branch.test = nullptr;
     return state;
 }
 
 IonBuilder::CFGState
 IonBuilder::CFGState::TableSwitch(jsbytecode *exitpc, MTableSwitch *ins)
 {
     CFGState state;
     state.state = TABLE_SWITCH;
@@ -1891,20 +1886,16 @@ IonBuilder::processIfElseTrueEnd(CFGStat
     // We've reached the end of the true branch of an if-else. Don't
     // create an edge yet, just transition to parsing the false branch.
     state.state = CFGState::IF_ELSE_FALSE;
     state.branch.ifTrue = current;
     state.stopAt = state.branch.falseEnd;
     pc = state.branch.ifFalse->pc();
     setCurrentAndSpecializePhis(state.branch.ifFalse);
     graph().moveBlockToEnd(current);
-
-    if (state.branch.test)
-        filterTypesAtTest(state.branch.test);
-
     return ControlStatus_Jumped;
 }
 
 IonBuilder::ControlStatus
 IonBuilder::processIfElseFalseEnd(CFGState &state)
 {
     // Update the state to have the latest block from the false path.
     state.branch.ifFalse = current;
@@ -3006,70 +2997,16 @@ IonBuilder::tableSwitch(JSOp op, jssrcno
     if (!cfgStack_.append(state))
         return ControlStatus_Error;
 
     pc = current->pc();
     return ControlStatus_Jumped;
 }
 
 bool
-IonBuilder::filterTypesAtTest(MTest *test)
-{
-    JS_ASSERT(test->ifTrue() == current || test->ifFalse() == current);
-
-    bool trueBranch = test->ifTrue() == current;
-
-    MDefinition *subject = nullptr;
-    bool removeUndefined;
-    bool removeNull;
-
-    test->filtersUndefinedOrNull(trueBranch, &subject, &removeUndefined, &removeNull);
-
-    // The test filters no undefined or null.
-    if (!subject)
-        return true;
-
-    // There is no TypeSet that can get filtered.
-    if (!subject->resultTypeSet())
-        return true;
-
-    // Only do this optimization if the typeset does contains null or undefined.
-    if (!((removeUndefined && subject->resultTypeSet()->hasType(types::Type::UndefinedType())) ||
-        (removeNull && subject->resultTypeSet()->hasType(types::Type::NullType()))))
-    {
-        return true;
-    }
-
-    //printf("%d: replacing\n", script()->lineno());
-    // Find all values on the stack that correspond to the subject
-    // and replace it with a MIR with filtered TypeSet information.
-    // Create the replacement MIR lazily upon first occurence.
-    MDefinition *replace = nullptr;
-    for (uint32_t i = 0; i < current->stackDepth(); i++) {
-        if (current->getSlot(i) != subject)
-            continue;
-
-        // Create replacement MIR with filtered TypesSet.
-        if (!replace) {
-            types::TemporaryTypeSet *type =
-                subject->resultTypeSet()->filter(alloc_->lifoAlloc(), removeUndefined,
-                                                                      removeNull);
-            if (!type)
-                return false;
-
-            replace = ensureDefiniteTypeSet(subject, type);
-        }
-
-        current->setSlot(i, replace);
-    }
-
-   return true;
-}
-
-bool
 IonBuilder::jsop_label()
 {
     JS_ASSERT(JSOp(*pc) == JSOP_LABEL);
 
     jsbytecode *endpc = pc + GET_JUMP_OFFSET(pc);
     JS_ASSERT(endpc > pc);
 
     ControlFlowInfo label(cfgStack_.length(), endpc);
@@ -3477,17 +3414,17 @@ IonBuilder::jsop_ifeq(JSOp op)
     //    ...
     // Z: ...     ; join
     //
     // We want to parse the bytecode as if we were parsing the AST, so for the
     // IF_ELSE/COND cases, we use the source note and follow the GOTO. For the
     // IF case, the IFEQ offset is the join point.
     switch (SN_TYPE(sn)) {
       case SRC_IF:
-        if (!cfgStack_.append(CFGState::If(falseStart, test)))
+        if (!cfgStack_.append(CFGState::If(falseStart, ifFalse)))
             return false;
         break;
 
       case SRC_IF_ELSE:
       case SRC_COND:
       {
         // Infer the join point from the JSOP_GOTO[X] sitting here, then
         // assert as we much we can that this is the right GOTO.
@@ -3496,32 +3433,29 @@ IonBuilder::jsop_ifeq(JSOp op)
         JS_ASSERT(trueEnd < falseStart);
         JS_ASSERT(JSOp(*trueEnd) == JSOP_GOTO);
         JS_ASSERT(!info().getNote(gsn, trueEnd));
 
         jsbytecode *falseEnd = trueEnd + GetJumpOffset(trueEnd);
         JS_ASSERT(falseEnd > trueEnd);
         JS_ASSERT(falseEnd >= falseStart);
 
-        if (!cfgStack_.append(CFGState::IfElse(trueEnd, falseEnd, test)))
+        if (!cfgStack_.append(CFGState::IfElse(trueEnd, falseEnd, ifFalse)))
             return false;
         break;
       }
 
       default:
         MOZ_ASSUME_UNREACHABLE("unexpected source note type");
     }
 
     // Switch to parsing the true branch. Note that no PC update is needed,
     // it's the next instruction.
     setCurrentAndSpecializePhis(ifTrue);
 
-    // Filter the types in the true branch.
-    filterTypesAtTest(test);
-
     return true;
 }
 
 bool
 IonBuilder::jsop_try()
 {
     JS_ASSERT(JSOp(*pc) == JSOP_TRY);
 
@@ -6299,36 +6233,16 @@ IonBuilder::ensureDefiniteType(MDefiniti
         break;
       }
     }
 
     current->add(replace);
     return replace;
 }
 
-MDefinition *
-IonBuilder::ensureDefiniteTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
-{
-    // We cannot arbitrarily add a typeset to a definition. It can be shared
-    // in another path. So we always need to create a new MIR.
-
-    // Use ensureDefiniteType to do unboxing. If that happened the type can
-    // be added on the newly created unbox operation.
-    MDefinition *replace = ensureDefiniteType(def, types->getKnownTypeTag());
-    if (replace != def) {
-        replace->setResultTypeSet(types);
-        return replace;
-    }
-
-    // Create a NOP mir instruction to filter the typeset.
-    MFilterTypeSet *filter = MFilterTypeSet::New(alloc(), def, types);
-    current->add(filter);
-    return filter;
-}
-
 static size_t
 NumFixedSlots(JSObject *object)
 {
     // Note: we can't use object->numFixedSlots() here, as this will read the
     // shape and can race with the main thread if we are building off thread.
     // The allocation kind and object class (which goes through the type) can
     // be read freely, however.
     gc::AllocKind kind = object->tenuredGetAllocKind();
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -105,17 +105,16 @@ class IonBuilder : public MIRGenerator
         jsbytecode *stopAt;     // Bytecode at which to stop the processing loop.
 
         // For if structures, this contains branch information.
         union {
             struct {
                 MBasicBlock *ifFalse;
                 jsbytecode *falseEnd;
                 MBasicBlock *ifTrue;    // Set when the end of the true path is reached.
-                MTest *test;
             } branch;
             struct {
                 // Common entry point.
                 MBasicBlock *entry;
 
                 // Whether OSR is being performed for this loop.
                 bool osr;
 
@@ -196,18 +195,18 @@ class IonBuilder : public MIRGenerator
               case FOR_LOOP_BODY:
               case FOR_LOOP_UPDATE:
                 return true;
               default:
                 return false;
             }
         }
 
-        static CFGState If(jsbytecode *join, MTest *test);
-        static CFGState IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MTest *test);
+        static CFGState If(jsbytecode *join, MBasicBlock *ifFalse);
+        static CFGState IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MBasicBlock *ifFalse);
         static CFGState AndOr(jsbytecode *join, MBasicBlock *joinStart);
         static CFGState TableSwitch(jsbytecode *exitpc, MTableSwitch *ins);
         static CFGState CondSwitch(IonBuilder *builder, jsbytecode *exitpc, jsbytecode *defaultTarget);
         static CFGState Label(jsbytecode *exitpc);
         static CFGState Try(jsbytecode *exitpc, MBasicBlock *successor);
     };
 
     static int CmpSuccessors(const void *a, const void *b);
@@ -332,37 +331,31 @@ class IonBuilder : public MIRGenerator
     void rewriteParameters();
     bool initScopeChain(MDefinition *callee = nullptr);
     bool initArgumentsObject();
     bool pushConstant(const Value &v);
 
     MConstant *constant(const Value &v);
     MConstant *constantInt(int32_t i);
 
-    // Filter the type information at tests
-    bool filterTypesAtTest(MTest *test);
-
     // Add a guard which ensure that the set of type which goes through this
     // generated code correspond to the observed types for the bytecode.
     bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier);
 
     // As pushTypeBarrier, but will compute the needBarrier boolean itself based
     // on observed and the JSFunction that we're planning to call. The
     // JSFunction must be a DOM method or getter.
     bool pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func);
 
     // If definiteType is not known or def already has the right type, just
     // returns def.  Otherwise, returns an MInstruction that has that definite
     // type, infallibly unboxing ins as needed.  The new instruction will be
     // added to |current| in this case.
     MDefinition *ensureDefiniteType(MDefinition* def, JSValueType definiteType);
 
-    // Creates a MDefinition based on the given def improved with type as TypeSet.
-    MDefinition *ensureDefiniteTypeSet(MDefinition* def, types::TemporaryTypeSet *types);
-
     JSObject *getSingletonPrototype(JSFunction *target);
 
     MDefinition *createThisScripted(MDefinition *callee);
     MDefinition *createThisScriptedSingleton(JSFunction *target, MDefinition *callee);
     MDefinition *createThis(JSFunction *target, MDefinition *callee);
     MInstruction *createDeclEnvObject(MDefinition *callee, MDefinition *scopeObj);
     MInstruction *createCallObject(MDefinition *callee, MDefinition *scopeObj);
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2192,22 +2192,16 @@ LIRGenerator::visitStoreSlot(MStoreSlot 
         return add(new(alloc()) LStoreSlotT(useRegister(ins->slots()), useRegisterOrConstant(ins->value())),
                    ins);
     }
 
     return true;
 }
 
 bool
-LIRGenerator::visitFilterTypeSet(MFilterTypeSet *ins)
-{
-    return redefine(ins, ins->input());
-}
-
-bool
 LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
 {
     // Requesting a non-GC pointer is safe here since we never re-enter C++
     // from inside a type barrier test.
 
     const types::TemporaryTypeSet *types = ins->resultTypeSet();
     bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
 
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -161,17 +161,16 @@ class LIRGenerator : public LIRGenerator
     bool visitMaybeToDoubleElement(MMaybeToDoubleElement *ins);
     bool visitLoadSlot(MLoadSlot *ins);
     bool visitFunctionEnvironment(MFunctionEnvironment *ins);
     bool visitForkJoinContext(MForkJoinContext *ins);
     bool visitGuardThreadExclusive(MGuardThreadExclusive *ins);
     bool visitInterruptCheck(MInterruptCheck *ins);
     bool visitInterruptCheckPar(MInterruptCheckPar *ins);
     bool visitStoreSlot(MStoreSlot *ins);
-    bool visitFilterTypeSet(MFilterTypeSet *ins);
     bool visitTypeBarrier(MTypeBarrier *ins);
     bool visitMonitorTypes(MMonitorTypes *ins);
     bool visitPostWriteBarrier(MPostWriteBarrier *ins);
     bool visitArrayLength(MArrayLength *ins);
     bool visitSetArrayLength(MSetArrayLength *ins);
     bool visitTypedArrayLength(MTypedArrayLength *ins);
     bool visitTypedArrayElements(MTypedArrayElements *ins);
     bool visitNeuterCheck(MNeuterCheck *lir);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -220,22 +220,16 @@ MaybeCallable(MDefinition *op)
 
     types::TemporaryTypeSet *types = op->resultTypeSet();
     if (!types)
         return true;
 
     return types->maybeCallable();
 }
 
-MTest *
-MTest::New(TempAllocator &alloc, MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse)
-{
-    return new(alloc) MTest(ins, ifTrue, ifFalse);
-}
-
 void
 MTest::infer()
 {
     JS_ASSERT(operandMightEmulateUndefined());
 
     if (!MaybeEmulatesUndefined(getOperand(0)))
         markOperandCantEmulateUndefined();
 }
@@ -247,42 +241,16 @@ MTest::foldsTo(TempAllocator &alloc, boo
 
     if (op->isNot())
         return MTest::New(alloc, op->toNot()->operand(), ifFalse(), ifTrue());
 
     return this;
 }
 
 void
-MTest::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
-                              bool *filtersNull)
-{
-    MDefinition *ins = getOperand(0);
-    if (ins->isCompare()) {
-        ins->toCompare()->filtersUndefinedOrNull(trueBranch, subject, filtersUndefined, filtersNull);
-        return;
-    }
-
-    if (!trueBranch && ins->isNot()) {
-        *subject = ins->getOperand(0);
-        *filtersUndefined = *filtersNull = true;
-        return;
-    }
-
-    if (trueBranch) {
-        *subject = ins;
-        *filtersUndefined = *filtersNull = true;
-        return;
-    }
-
-    *filtersUndefined = *filtersNull = false;
-    *subject = nullptr;
-}
-
-void
 MDefinition::printOpcode(FILE *fp) const
 {
     PrintOpcodeName(fp, op());
     for (size_t j = 0, e = numOperands(); j < e; j++) {
         fprintf(fp, " ");
         getOperand(j)->printName(fp);
     }
 }
@@ -837,16 +805,22 @@ MFloor::trySpecializeFloat32(TempAllocat
     }
 
     if (type() == MIRType_Double)
         setResultType(MIRType_Float32);
 
     setPolicyType(MIRType_Float32);
 }
 
+MTest *
+MTest::New(TempAllocator &alloc, MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse)
+{
+    return new(alloc) MTest(ins, ifTrue, ifFalse);
+}
+
 MCompare *
 MCompare::New(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op)
 {
     return new(alloc) MCompare(left, right, op);
 }
 
 MCompare *
 MCompare::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op,
@@ -2572,47 +2546,16 @@ MCompare::trySpecializeFloat32(TempAlloc
         if (lhs->type() == MIRType_Float32)
             ConvertDefinitionToDouble<0>(alloc, lhs, this);
         if (rhs->type() == MIRType_Float32)
             ConvertDefinitionToDouble<1>(alloc, rhs, this);
     }
 }
 
 void
-MCompare::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
-                                 bool *filtersNull)
-{
-    *filtersNull = *filtersUndefined = false;
-    *subject = nullptr;
-
-    if (compareType() != Compare_Undefined && compareType() != Compare_Null)
-        return;
-
-    JS_ASSERT(jsop() == JSOP_STRICTNE || jsop() == JSOP_NE ||
-              jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ);
-
-    // JSOP_*NE only removes undefined/null from if/true branch
-    if (!trueBranch && (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE))
-        return;
-
-    // JSOP_*EQ only removes undefined/null from else/false branch
-    if (trueBranch && (jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ))
-        return;
-
-    if (jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE) {
-        *filtersUndefined = compareType() == Compare_Undefined;
-        *filtersNull = compareType() == Compare_Null;
-    } else {
-        *filtersUndefined = *filtersNull = true;
-    }
-
-    *subject = lhs();
-}
-
-void
 MNot::infer()
 {
     JS_ASSERT(operandMightEmulateUndefined());
 
     if (!MaybeEmulatesUndefined(getOperand(0)))
         markOperandCantEmulateUndefined();
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1316,18 +1316,16 @@ class MTest
         return this;
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void infer();
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
-                                bool *filtersNull);
 
     void markOperandCantEmulateUndefined() {
         operandMightEmulateUndefined_ = false;
     }
     bool operandMightEmulateUndefined() const {
         return operandMightEmulateUndefined_;
     }
 #ifdef DEBUG
@@ -2275,18 +2273,16 @@ class MCompare
     INSTRUCTION_HEADER(Compare)
     static MCompare *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op);
     static MCompare *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op,
                               CompareType compareType);
 
     bool tryFold(bool *result);
     bool evaluateConstantOperands(bool *result);
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
-                                bool *filtersNull);
 
     void infer(BaselineInspector *inspector, jsbytecode *pc);
     CompareType compareType() const {
         return compareType_;
     }
     bool isInt32Comparison() const {
         return compareType() == Compare_Int32 ||
                compareType() == Compare_Int32MaybeCoerceBoth ||
@@ -8770,47 +8766,16 @@ class MGuardThreadExclusive
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
-class MFilterTypeSet
-  : public MUnaryInstruction
-{
-    MFilterTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
-      : MUnaryInstruction(def)
-    {
-        JS_ASSERT(!types->unknown());
-
-        MIRType type = MIRTypeFromValueType(types->getKnownTypeTag());
-        setResultType(type);
-        setResultTypeSet(types);
-    }
-
-  public:
-    INSTRUCTION_HEADER(FilterTypeSet)
-
-    static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
-        return new(alloc) MFilterTypeSet(def, types);
-    }
-
-    bool congruentTo(MDefinition *def) const {
-        return false;
-    }
-    AliasSet getAliasSet() const {
-        return AliasSet::None();
-    }
-    virtual bool neverHoist() const {
-        return resultTypeSet()->empty();
-    }
-};
-
 // Given a value, guard that the value is in a particular TypeSet, then returns
 // that value.
 class MTypeBarrier
   : public MUnaryInstruction,
     public TypeBarrierPolicy
 {
     MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types)
       : MUnaryInstruction(def)
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -109,17 +109,16 @@ namespace jit {
     _(Slots)                                                                \
     _(Elements)                                                             \
     _(ConstantElements)                                                     \
     _(ConvertElementsToDoubles)                                             \
     _(MaybeToDoubleElement)                                                 \
     _(LoadSlot)                                                             \
     _(StoreSlot)                                                            \
     _(FunctionEnvironment)                                                  \
-    _(FilterTypeSet)                                                        \
     _(TypeBarrier)                                                          \
     _(MonitorTypes)                                                         \
     _(PostWriteBarrier)                                                     \
     _(GetPropertyCache)                                                     \
     _(GetPropertyPolymorphic)                                               \
     _(SetPropertyPolymorphic)                                               \
     _(GetElementCache)                                                      \
     _(SetElementCache)                                                      \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -196,17 +196,16 @@ class ParallelSafetyVisitor : public MIn
     CUSTOM_OP(Lambda)
     UNSAFE_OP(ImplicitThis)
     SAFE_OP(Slots)
     SAFE_OP(Elements)
     SAFE_OP(ConstantElements)
     SAFE_OP(LoadSlot)
     WRITE_GUARDED_OP(StoreSlot, slots)
     SAFE_OP(FunctionEnvironment) // just a load of func env ptr
-    SAFE_OP(FilterTypeSet)
     SAFE_OP(TypeBarrier) // causes a bailout if the type is not found: a-ok with us
     SAFE_OP(MonitorTypes) // causes a bailout if the type is not found: a-ok with us
     UNSAFE_OP(PostWriteBarrier)
     SAFE_OP(GetPropertyCache)
     SAFE_OP(GetPropertyPolymorphic)
     UNSAFE_OP(SetPropertyPolymorphic)
     SAFE_OP(GetElementCache)
     WRITE_GUARDED_OP(SetElementCache, object)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -487,32 +487,16 @@ TemporaryTypeSet *
 TypeSet::clone(LifoAlloc *alloc) const
 {
     TemporaryTypeSet *res = alloc->new_<TemporaryTypeSet>();
     if (!res || !clone(alloc, res))
         return nullptr;
     return res;
 }
 
-TemporaryTypeSet *
-TypeSet::filter(LifoAlloc *alloc, bool filterUndefined, bool filterNull) const
-{
-    TemporaryTypeSet *res = clone(alloc);
-    if (!res)
-        return nullptr;
-
-    if (filterUndefined)
-        res->flags = flags & ~TYPE_FLAG_UNDEFINED;
-
-    if (filterNull)
-        res->flags = flags & ~TYPE_FLAG_NULL;
-
-    return res;
-}
-
 /* static */ TemporaryTypeSet *
 TypeSet::unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc)
 {
     TemporaryTypeSet *res = alloc->new_<TemporaryTypeSet>(a->baseFlags() | b->baseFlags(),
                                                           static_cast<TypeObjectKey**>(nullptr));
     if (!res)
         return nullptr;
 
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -569,19 +569,16 @@ class TypeSet
 
     /* Forward all types in this set to the specified constraint. */
     void addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
 
     // Clone a type set into an arbitrary allocator.
     TemporaryTypeSet *clone(LifoAlloc *alloc) const;
     bool clone(LifoAlloc *alloc, TemporaryTypeSet *result) const;
 
-    // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
-    TemporaryTypeSet *filter(LifoAlloc *alloc, bool filterUndefined, bool filterNull) const;
-
   protected:
     uint32_t baseObjectCount() const {
         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
     }
     inline void setBaseObjectCount(uint32_t count);
 
     inline void clearObjects();
 };