Bug 1201459: IonMonkey - Fix typepolicy of MFilterTypeSet with MIRType_Float32, r=bbouvier,nbp
authorHannes Verschore <hv1989@gmail.com>
Fri, 11 Sep 2015 14:27:22 +0200
changeset 294622 9f8526509f5a19a6b89ee7178bba9c5545e12005
parent 294621 f49b4cddbc850916b1d2ec85613c4a649d5eadae
child 294623 e6155c93aa202d11b696fcee36b9be127f88ca3d
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier, nbp
bugs1201459
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1201459: IonMonkey - Fix typepolicy of MFilterTypeSet with MIRType_Float32, r=bbouvier,nbp
js/src/jit-test/tests/ion/bug1201459.js
js/src/jit/IonAnalysis.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/TypePolicy.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1201459.js
@@ -0,0 +1,5 @@
+// |jit-test| error:ReferenceError
+function f() {
+        (x ? Math.fround(0) : x ? a : x) && b;
+}
+f(Math.fround);
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1161,16 +1161,19 @@ TypeAnalyzer::insertConversions()
                 phi->type() == MIRType_MagicUninitializedLexical)
             {
                 replaceRedundantPhi(phi);
                 block->discardPhi(phi);
             } else {
                 adjustPhiInputs(phi);
             }
         }
+
+        // AdjustInputs can add/remove/mutate instructions before and after the
+        // current instruction. Only increment the iterator after it is finished.
         for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) {
             if (!adjustInputs(*iter))
                 return false;
         }
     }
     return true;
 }
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -604,16 +604,40 @@ MDefinition::justReplaceAllUsesWith(MDef
     MOZ_ASSERT(dom != this);
 
     for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i)
         i->setProducerUnchecked(dom);
     dom->uses_.takeElements(uses_);
 }
 
 void
+MDefinition::justReplaceAllUsesWithExcept(MDefinition* dom)
+{
+    MOZ_ASSERT(dom != nullptr);
+    MOZ_ASSERT(dom != this);
+
+    // Move all uses to new dom. Save the use of the dominating instruction.
+    MUse *exceptUse = nullptr;
+    for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) {
+        if (i->consumer() != dom) {
+            i->setProducerUnchecked(dom);
+        } else {
+            MOZ_ASSERT(!exceptUse);
+            exceptUse = *i;
+        }
+    }
+    dom->uses_.takeElements(uses_);
+
+    // Restore the use to the original definition.
+    dom->uses_.remove(exceptUse);
+    exceptUse->setProducerUnchecked(this);
+    uses_.pushFront(exceptUse);
+}
+
+void
 MDefinition::optimizeOutAllUses(TempAllocator& alloc)
 {
     for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
         MUse* use = *i++;
         MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc);
 
         // Update the resume point operand to use the optimized-out constant.
         use->setProducerUnchecked(constant);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -734,16 +734,20 @@ class MDefinition : public MNode
 
     // Replace the current instruction by a dominating instruction |dom| in all
     // uses of the current instruction.
     void replaceAllUsesWith(MDefinition* dom);
 
     // Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands.
     void justReplaceAllUsesWith(MDefinition* dom);
 
+    // Like justReplaceAllUsesWith, but doesn't replace its own use to the
+    // dominating instruction (which would introduce a circular dependency).
+    void justReplaceAllUsesWithExcept(MDefinition* dom);
+
     // Replace the current instruction by an optimized-out constant in all uses
     // of the current instruction. Note, that optimized-out constant should not
     // be observed, and thus they should not flow in any computation.
     void optimizeOutAllUses(TempAllocator& alloc);
 
     // Replace the current instruction by a dominating instruction |dom| in all
     // instruction, but keep the current instruction for resume point and
     // instruction which are recovered on bailouts.
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -1075,16 +1075,40 @@ ClampPolicy::adjustInputs(TempAllocator&
 
 bool
 FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
 {
     MOZ_ASSERT(ins->numOperands() == 1);
     MIRType inputType = ins->getOperand(0)->type();
     MIRType outputType = ins->type();
 
+    // Special case when output is a Float32, but input isn't.
+    if (outputType == MIRType_Float32 && inputType != MIRType_Float32) {
+        // Create a MToFloat32 to add between the MFilterTypeSet and
+        // its uses.
+        MInstruction* replace = MToFloat32::New(alloc, ins);
+        ins->justReplaceAllUsesWithExcept(replace);
+        ins->block()->insertAfter(ins, replace);
+
+        // Reset the type to not MIRType_Float32
+        // Note: setResultType shouldn't happen in TypePolicies,
+        //       Here it is fine, since there is just one use we just
+        //       added ourself. And the resulting type after MToFloat32
+        //       equals the original type.
+        ins->setResultType(ins->resultTypeSet()->getKnownMIRType());
+        outputType = ins->type();
+
+        // Do the type analysis
+        if (!replace->typePolicy()->adjustInputs(alloc, replace))
+            return false;
+
+        // Fall through to let the MFilterTypeSet adjust its input based
+        // on its new type.
+    }
+
     // Input and output type are already in accordance.
     if (inputType == outputType)
         return true;
 
     // Output is a value, box the input.
     if (outputType == MIRType_Value) {
         MOZ_ASSERT(inputType != MIRType_Value);
         ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));