Bug 1246658 part 5 - Support int64 constants, add MIRType_Int64. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 18 Feb 2016 14:18:07 +0100
changeset 284742 2da9867fc1d2
parent 284741 5658512697c4
child 284743 b34a59d6ffe8
push id30013
push usercbook@mozilla.com
push date2016-02-19 11:02 +0000
treeherdermozilla-central@a87d6d52c1fc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1246658
milestone47.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 1246658 part 5 - Support int64 constants, add MIRType_Int64. r=luke
js/src/jit/IonAnalysis.cpp
js/src/jit/IonTypes.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/RangeAnalysis.cpp
js/src/jit/shared/CodeGenerator-shared-inl.h
js/src/jsapi-tests/testJitDCEinGVN.cpp
js/src/jsapi-tests/testJitFoldsTo.cpp
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1264,17 +1264,19 @@ GuessPhiType(MPhi* phi, bool* hasInputsW
                 convertibleToFloat32 = true;
             continue;
         }
         if (type != in->type()) {
             if (convertibleToFloat32 && in->type() == MIRType_Float32) {
                 // If we only saw definitions that can be converted into Float32 before and
                 // encounter a Float32 value, promote previous values to Float32
                 type = MIRType_Float32;
-            } else if (IsNumberType(type) && IsNumberType(in->type())) {
+            } else if (IsTypeRepresentableAsDouble(type) &&
+                       IsTypeRepresentableAsDouble(in->type()))
+            {
                 // Specialize phis with int32 and double operands as double.
                 type = MIRType_Double;
                 convertibleToFloat32 &= in->canProduceFloat32();
             } else {
                 return MIRType_Value;
             }
         }
     }
@@ -1324,17 +1326,19 @@ TypeAnalyzer::propagateSpecialization(MP
                 (phi->type() == MIRType_Int32 && phi->canProduceFloat32() && use->type() == MIRType_Float32))
             {
                 if (!respecialize(use, MIRType_Float32))
                     return false;
                 continue;
             }
 
             // Specialize phis with int32 and double operands as double.
-            if (IsNumberType(use->type()) && IsNumberType(phi->type())) {
+            if (IsTypeRepresentableAsDouble(use->type()) &&
+                IsTypeRepresentableAsDouble(phi->type()))
+            {
                 if (!respecialize(use, MIRType_Double))
                     return false;
                 continue;
             }
 
             // This phi in our use chain can now no longer be specialized.
             if (!respecialize(use, MIRType_Value))
                 return false;
@@ -2496,16 +2500,17 @@ IsResumableMIRType(MIRType type)
       case MIRType_None:
       case MIRType_Slots:
       case MIRType_Elements:
       case MIRType_Pointer:
       case MIRType_Shape:
       case MIRType_ObjectGroup:
       case MIRType_Doublex2: // NYI, see also RSimdBox::recover
       case MIRType_SinCosDouble:
+      case MIRType_Int64:
         return false;
     }
     MOZ_CRASH("Unknown MIRType.");
 }
 
 static void
 AssertResumableOperands(MNode* node)
 {
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -394,16 +394,17 @@ class SimdConstant {
 // specialized type. Furthermore, anything < String has trivial conversion to
 // a number.
 enum MIRType
 {
     MIRType_Undefined,
     MIRType_Null,
     MIRType_Boolean,
     MIRType_Int32,
+    MIRType_Int64,
     MIRType_Double,
     MIRType_Float32,
     MIRType_String,
     MIRType_Symbol,
     MIRType_Object,
     MIRType_MagicOptimizedArguments,   // JS_OPTIMIZED_ARGUMENTS magic value.
     MIRType_MagicOptimizedOut,         // JS_OPTIMIZED_OUT magic value.
     MIRType_MagicHole,                 // JS_ELEMENTS_HOLE magic value.
@@ -499,16 +500,18 @@ StringFromMIRType(MIRType type)
     case MIRType_Undefined:
       return "Undefined";
     case MIRType_Null:
       return "Null";
     case MIRType_Boolean:
       return "Bool";
     case MIRType_Int32:
       return "Int32";
+    case MIRType_Int64:
+      return "Int64";
     case MIRType_Double:
       return "Double";
     case MIRType_Float32:
       return "Float32";
     case MIRType_String:
       return "String";
     case MIRType_Symbol:
       return "Symbol";
@@ -552,17 +555,28 @@ StringFromMIRType(MIRType type)
       return "Doublex2";
   }
   MOZ_CRASH("Unknown MIRType.");
 }
 
 static inline bool
 IsNumberType(MIRType type)
 {
-    return type == MIRType_Int32 || type == MIRType_Double || type == MIRType_Float32;
+    return type == MIRType_Int32 ||
+           type == MIRType_Double ||
+           type == MIRType_Float32 ||
+           type == MIRType_Int64;
+}
+
+static inline bool
+IsTypeRepresentableAsDouble(MIRType type)
+{
+    return type == MIRType_Int32 ||
+           type == MIRType_Double ||
+           type == MIRType_Float32;
 }
 
 static inline bool
 IsFloatType(MIRType type)
 {
     return type == MIRType_Int32 || type == MIRType_Float32;
 }
 
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1275,17 +1275,17 @@ IonBuilder::inlineMathPowHelper(MDefinit
         return InliningStatus_NotInlined;
 
     MDefinition* base = lhs;
     MDefinition* power = rhs;
     MDefinition* output = nullptr;
 
     // Optimize some constant powers.
     if (rhs->isConstant()) {
-        double pow = rhs->toConstant()->toNumber();
+        double pow = rhs->toConstant()->numberToDouble();
 
         // Math.pow(x, 0.5) is a sqrt with edge-case detection.
         if (pow == 0.5) {
             MPowHalf* half = MPowHalf::New(alloc(), base);
             current->add(half);
             output = half;
         }
 
@@ -1481,17 +1481,17 @@ IonBuilder::inlineMathMinMax(CallInfo& c
             if (!int32_cases.append(arg))
                 return InliningStatus_Error;
             break;
           case MIRType_Double:
           case MIRType_Float32:
             // Don't force a double MMinMax for arguments that would be a NOP
             // when doing an integer MMinMax.
             if (arg->isConstant()) {
-                double cte = arg->toConstant()->toNumber();
+                double cte = arg->toConstant()->numberToDouble();
                 // min(int32, cte >= INT32_MAX) = int32
                 if (cte >= INT32_MAX && !max)
                     break;
                 // max(int32, cte <= INT32_MIN) = int32
                 if (cte <= INT32_MIN && max)
                     break;
             }
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -80,17 +80,18 @@ MDefinition::PrintOpcodeName(GenericPrin
 }
 
 static MConstant*
 EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* ptypeChange = nullptr)
 {
     MDefinition* left = ins->getOperand(0);
     MDefinition* right = ins->getOperand(1);
 
-    MOZ_ASSERT(IsNumberType(left->type()) && IsNumberType(right->type()));
+    MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()));
+    MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()));
 
     if (!left->isConstant() || !right->isConstant())
         return nullptr;
 
     MConstant* lhs = left->toConstant();
     MConstant* rhs = right->toConstant();
     Value ret = UndefinedValue();
 
@@ -109,35 +110,35 @@ EvaluateConstantOperands(TempAllocator& 
         break;
       case MDefinition::Op_Rsh:
         ret = Int32Value(lhs->toInt32() >> (rhs->toInt32() & 0x1F));
         break;
       case MDefinition::Op_Ursh:
         ret.setNumber(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F));
         break;
       case MDefinition::Op_Add:
-        ret.setNumber(lhs->toNumber() + rhs->toNumber());
+        ret.setNumber(lhs->numberToDouble() + rhs->numberToDouble());
         break;
       case MDefinition::Op_Sub:
-        ret.setNumber(lhs->toNumber() - rhs->toNumber());
+        ret.setNumber(lhs->numberToDouble() - rhs->numberToDouble());
         break;
       case MDefinition::Op_Mul:
-        ret.setNumber(lhs->toNumber() * rhs->toNumber());
+        ret.setNumber(lhs->numberToDouble() * rhs->numberToDouble());
         break;
       case MDefinition::Op_Div:
         if (ins->toDiv()->isUnsigned())
             ret.setInt32(rhs->isInt32(0) ? 0 : uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32()));
         else
-            ret.setNumber(NumberDiv(lhs->toNumber(), rhs->toNumber()));
+            ret.setNumber(NumberDiv(lhs->numberToDouble(), rhs->numberToDouble()));
         break;
       case MDefinition::Op_Mod:
         if (ins->toMod()->isUnsigned())
             ret.setInt32(rhs->isInt32(0) ? 0 : uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32()));
         else
-            ret.setNumber(NumberMod(lhs->toNumber(), rhs->toNumber()));
+            ret.setNumber(NumberMod(lhs->numberToDouble(), rhs->numberToDouble()));
         break;
       default:
         MOZ_CRASH("NYI");
     }
 
     // setNumber eagerly transforms a number to int32.
     // Transform back to double, if the output type is double.
     if (ins->type() == MIRType_Double && ret.isInt32())
@@ -161,17 +162,17 @@ EvaluateExactReciprocal(TempAllocator& a
 
     MDefinition* left = ins->getOperand(0);
     MDefinition* right = ins->getOperand(1);
 
     if (!right->isConstant())
         return nullptr;
 
     int32_t num;
-    if (!mozilla::NumberIsInt32(right->toConstant()->toNumber(), &num))
+    if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num))
         return nullptr;
 
     // check if rhs is a power of two
     if (mozilla::Abs(num) & (mozilla::Abs(num) - 1))
         return nullptr;
 
     Value ret;
     ret.setDouble(1.0 / (double) num);
@@ -666,16 +667,22 @@ MConstant::New(TempAllocator& alloc, con
 MConstant*
 MConstant::NewFloat32(TempAllocator& alloc, double d)
 {
     MOZ_ASSERT(IsNaN(d) || d == double(float(d)));
     return new(alloc) MConstant(float(d));
 }
 
 MConstant*
+MConstant::NewInt64(TempAllocator& alloc, int64_t i)
+{
+    return new(alloc) MConstant(i);
+}
+
+MConstant*
 MConstant::NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type)
 {
     if (type == MIRType_Float32)
         return NewFloat32(alloc, v.toNumber());
     MConstant* res = New(alloc, v);
     MOZ_ASSERT(res->type() == type);
     return res;
 }
@@ -804,32 +811,40 @@ MConstant::MConstant(JSObject* obj)
 
 MConstant::MConstant(float f)
 {
     setResultType(MIRType_Float32);
     payload_.f = f;
     setMovable();
 }
 
+MConstant::MConstant(int64_t i)
+{
+    setResultType(MIRType_Int64);
+    payload_.i64 = i;
+    setMovable();
+}
+
 #ifdef DEBUG
 void
 MConstant::assertInitializedPayload() const
 {
     // valueHash() and equals() expect the unused payload bits to be
     // initialized to zero. Assert this in debug builds.
 
     switch (type()) {
       case MIRType_Int32:
       case MIRType_Float32:
         MOZ_ASSERT((payload_.asBits >> 32) == 0);
         break;
       case MIRType_Boolean:
         MOZ_ASSERT((payload_.asBits >> 1) == 0);
         break;
       case MIRType_Double:
+      case MIRType_Int64:
         break;
       case MIRType_String:
       case MIRType_Object:
       case MIRType_Symbol:
         MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0);
         break;
       default:
         MOZ_ASSERT(IsNullOrUndefined(type()) || IsMagicType(type()));
@@ -936,17 +951,17 @@ MConstant::printOpcode(GenericPrinter& o
       default:
         MOZ_CRASH("unexpected type");
     }
 }
 
 bool
 MConstant::canProduceFloat32() const
 {
-    if (!IsNumberType(type()))
+    if (!isTypeRepresentableAsDouble())
         return false;
 
     if (type() == MIRType_Int32)
         return IsFloat32Representable(static_cast<double>(toInt32()));
     if (type() == MIRType_Double)
         return IsFloat32Representable(toDouble());
     MOZ_ASSERT(type() == MIRType_Float32);
     return true;
@@ -1062,17 +1077,17 @@ MSimdValueX4::foldsTo(TempAllocator& all
             for (size_t i = 0; i < 4; ++i)
                 a[i] = getOperand(i)->toConstant()->toInt32();
             cst = SimdConstant::CreateX4(a);
             break;
           }
           case MIRType_Float32x4: {
             float a[4];
             for (size_t i = 0; i < 4; ++i)
-                a[i] = getOperand(i)->toConstant()->toNumber();
+                a[i] = getOperand(i)->toConstant()->numberToDouble();
             cst = SimdConstant::CreateX4(a);
             break;
           }
           default: MOZ_CRASH("unexpected type in MSimdValueX4::foldsTo");
         }
 
         return MSimdConstant::New(alloc, cst, type());
     }
@@ -1098,17 +1113,17 @@ MSimdSplatX4::foldsTo(TempAllocator& all
         break;
       }
       case MIRType_Int32x4: {
         int32_t v = op->toConstant()->toInt32();
         cst = SimdConstant::SplatX4(v);
         break;
       }
       case MIRType_Float32x4: {
-        float v = op->toConstant()->toNumber();
+        float v = op->toConstant()->numberToDouble();
         cst = SimdConstant::SplatX4(v);
         break;
       }
       default: MOZ_CRASH("unexpected type in MSimdSplatX4::foldsTo");
     }
 
     return MSimdConstant::New(alloc, cst, type());
 }
@@ -1441,20 +1456,20 @@ MMathFunction::printOpcode(GenericPrinte
     MDefinition::printOpcode(out);
     out.printf(" %s", FunctionName(function()));
 }
 
 MDefinition*
 MMathFunction::foldsTo(TempAllocator& alloc)
 {
     MDefinition* input = getOperand(0);
-    if (!input->isConstant() || !input->toConstant()->isNumber())
+    if (!input->isConstant() || !input->toConstant()->isTypeRepresentableAsDouble())
         return this;
 
-    double in = input->toConstant()->toNumber();
+    double in = input->toConstant()->numberToDouble();
     double out;
     switch (function_) {
       case Log:
         out = js::math_log_uncached(in);
         break;
       case Sin:
         out = js::math_sin_uncached(in);
         break;
@@ -2012,17 +2027,17 @@ MPhi::foldsTernary()
         !falseDef->block()->dominates(falsePred))
     {
         return nullptr;
     }
 
     // If testArg is an int32 type we can:
     // - fold testArg ? testArg : 0 to testArg
     // - fold testArg ? 0 : testArg to 0
-    if (testArg->type() == MIRType_Int32 && c->toNumber() == 0) {
+    if (testArg->type() == MIRType_Int32 && c->numberToDouble() == 0) {
         // When folding to the constant we need to hoist it.
         if (trueDef == c && !c->block()->dominates(block()))
             c->block()->moveBefore(pred->lastIns(), c);
         return trueDef;
     }
 
     // If testArg is a string type we can:
     // - fold testArg ? testArg : "" to testArg
@@ -2154,17 +2169,17 @@ MakeMIRTypeSet(MIRType type)
 
 bool
 jit::MergeTypes(MIRType* ptype, TemporaryTypeSet** ptypeSet,
                 MIRType newType, TemporaryTypeSet* newTypeSet)
 {
     if (newTypeSet && newTypeSet->empty())
         return true;
     if (newType != *ptype) {
-        if (IsNumberType(newType) && IsNumberType(*ptype)) {
+        if (IsTypeRepresentableAsDouble(newType) && IsTypeRepresentableAsDouble(*ptype)) {
             *ptype = MIRType_Double;
         } else if (*ptype != MIRType_Value) {
             if (!*ptypeSet) {
                 *ptypeSet = MakeMIRTypeSet(*ptype);
                 if (!*ptypeSet)
                     return false;
             }
             *ptype = MIRType_Value;
@@ -2388,17 +2403,17 @@ MCall::addArg(size_t argnum, MDefinition
 }
 
 static inline bool
 IsConstant(MDefinition* def, double v)
 {
     if (!def->isConstant())
         return false;
 
-    return NumbersAreIdentical(def->toConstant()->toNumber(), v);
+    return NumbersAreIdentical(def->toConstant()->numberToDouble(), v);
 }
 
 MDefinition*
 MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc)
 {
     if (specialization_ != MIRType_Int32)
         return this;
 
@@ -2802,21 +2817,24 @@ MDefinition*
 MMinMax::foldsTo(TempAllocator& alloc)
 {
     if (!lhs()->isConstant() && !rhs()->isConstant())
         return this;
 
     // Directly apply math utility to compare the rhs() and lhs() when
     // they are both constants.
     if (lhs()->isConstant() && rhs()->isConstant()) {
-        if (!lhs()->toConstant()->isNumber() || !rhs()->toConstant()->isNumber())
+        if (!lhs()->toConstant()->isTypeRepresentableAsDouble() ||
+            !rhs()->toConstant()->isTypeRepresentableAsDouble())
+        {
             return this;
-
-        double lnum = lhs()->toConstant()->toNumber();
-        double rnum = rhs()->toConstant()->toNumber();
+        }
+
+        double lnum = lhs()->toConstant()->numberToDouble();
+        double rnum = rhs()->toConstant()->numberToDouble();
         double result;
         if (isMax())
             result = js::math_max_impl(lnum, rnum);
         else
             result = js::math_min_impl(lnum, rnum);
 
         // The folded MConstant should maintain the same MIRType with
         // the original MMinMax.
@@ -2832,26 +2850,32 @@ MMinMax::foldsTo(TempAllocator& alloc)
         }
     }
 
     MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
     MConstant* constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
 
     if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) {
         // min(int32, cte >= INT32_MAX) = int32
-        if (constant->isNumber() && constant->toNumber() >= INT32_MAX && !isMax()) {
+        if (!isMax() &&
+            constant->isTypeRepresentableAsDouble() &&
+            constant->numberToDouble() >= INT32_MAX)
+        {
             MLimitedTruncate* limit =
                 MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
             block()->insertBefore(this, limit);
             MToDouble* toDouble = MToDouble::New(alloc, limit);
             return toDouble;
         }
 
         // max(int32, cte <= INT32_MIN) = int32
-        if (constant->isNumber() && constant->toNumber() <= INT32_MIN && isMax()) {
+        if (isMax() &&
+            constant->isTypeRepresentableAsDouble() &&
+            constant->numberToDouble() <= INT32_MIN)
+        {
             MLimitedTruncate* limit =
                 MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
             block()->insertBefore(this, limit);
             MToDouble* toDouble = MToDouble::New(alloc, limit);
             return toDouble;
         }
     }
     return this;
@@ -3233,17 +3257,17 @@ MCompare::determineCompareType(JSOp op, 
     if (!strictEq &&
         (lhs == MIRType_Int32 || lhs == MIRType_Boolean) &&
         (rhs == MIRType_Int32 || rhs == MIRType_Boolean))
     {
         return Compare_Int32MaybeCoerceBoth;
     }
 
     // Numeric comparisons against a double coerce to double.
-    if (IsNumberType(lhs) && IsNumberType(rhs))
+    if (IsTypeRepresentableAsDouble(lhs) && IsTypeRepresentableAsDouble(rhs))
         return Compare_Double;
 
     // Any comparison is allowed except strict eq.
     if (!strictEq && IsFloatingPointType(rhs) && SafelyCoercesToDouble(left))
         return Compare_DoubleMaybeCoerceLHS;
     if (!strictEq && IsFloatingPointType(lhs) && SafelyCoercesToDouble(right))
         return Compare_DoubleMaybeCoerceRHS;
 
@@ -3643,17 +3667,17 @@ MToInt32::foldsTo(TempAllocator& alloc)
                        convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly);
             return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean()));
           case MIRType_Int32:
             return MConstant::New(alloc, Int32Value(input->toConstant()->toInt32()));
           case MIRType_Float32:
           case MIRType_Double:
             int32_t ival;
             // Only the value within the range of Int32 can be substituted as constant.
-            if (mozilla::NumberEqualsInt32(input->toConstant()->toNumber(), &ival))
+            if (mozilla::NumberEqualsInt32(input->toConstant()->numberToDouble(), &ival))
                 return MConstant::New(alloc, Int32Value(ival));
             break;
           default:
             break;
         }
     }
 
     if (input->type() == MIRType_Int32)
@@ -3691,18 +3715,18 @@ MToDouble::foldsTo(TempAllocator& alloc)
 {
     MDefinition* input = getOperand(0);
     if (input->isBox())
         input = input->getOperand(0);
 
     if (input->type() == MIRType_Double)
         return input;
 
-    if (input->isConstant() && input->toConstant()->isNumber()) {
-        double out = input->toConstant()->toNumber();
+    if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) {
+        double out = input->toConstant()->numberToDouble();
         return MConstant::New(alloc, DoubleValue(out));
     }
 
     return this;
 }
 
 MDefinition*
 MToFloat32::foldsTo(TempAllocator& alloc)
@@ -3713,18 +3737,18 @@ MToFloat32::foldsTo(TempAllocator& alloc
 
     if (input->type() == MIRType_Float32)
         return input;
 
     // If x is a Float32, Float32(Double(x)) == x
     if (input->isToDouble() && input->toToDouble()->input()->type() == MIRType_Float32)
         return input->toToDouble()->input();
 
-    if (input->isConstant() && input->toConstant()->isNumber())
-        return MConstant::NewFloat32(alloc, float(input->toConstant()->toNumber()));
+    if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble())
+        return MConstant::NewFloat32(alloc, float(input->toConstant()->numberToDouble()));
 
     return this;
 }
 
 MDefinition*
 MToString::foldsTo(TempAllocator& alloc)
 {
     MDefinition* in = input();
@@ -3735,18 +3759,18 @@ MToString::foldsTo(TempAllocator& alloc)
         return in;
     return this;
 }
 
 MDefinition*
 MClampToUint8::foldsTo(TempAllocator& alloc)
 {
     if (MConstant* inputConst = input()->maybeConstantValue()) {
-        if (inputConst->isNumber()) {
-            int32_t clamped = ClampDoubleToUint8(inputConst->toNumber());
+        if (inputConst->isTypeRepresentableAsDouble()) {
+            int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble());
             return MConstant::New(alloc, Int32Value(clamped));
         }
     }
     return this;
 }
 
 bool
 MCompare::tryFoldEqualOperands(bool* result)
@@ -4078,39 +4102,39 @@ MCompare::evaluateConstantOperands(TempA
             break;
           default:
             MOZ_CRASH("Unexpected op.");
         }
 
         return true;
     }
 
-    if (!lhs->isNumber() || !rhs->isNumber())
+    if (!lhs->isTypeRepresentableAsDouble() || !rhs->isTypeRepresentableAsDouble())
         return false;
 
     switch (jsop_) {
       case JSOP_LT:
-        *result = (lhs->toNumber() < rhs->toNumber());
+        *result = (lhs->numberToDouble() < rhs->numberToDouble());
         break;
       case JSOP_LE:
-        *result = (lhs->toNumber() <= rhs->toNumber());
+        *result = (lhs->numberToDouble() <= rhs->numberToDouble());
         break;
       case JSOP_GT:
-        *result = (lhs->toNumber() > rhs->toNumber());
+        *result = (lhs->numberToDouble() > rhs->numberToDouble());
         break;
       case JSOP_GE:
-        *result = (lhs->toNumber() >= rhs->toNumber());
+        *result = (lhs->numberToDouble() >= rhs->numberToDouble());
         break;
       case JSOP_STRICTEQ: // Fall through.
       case JSOP_EQ:
-        *result = (lhs->toNumber() == rhs->toNumber());
+        *result = (lhs->numberToDouble() == rhs->numberToDouble());
         break;
       case JSOP_STRICTNE: // Fall through.
       case JSOP_NE:
-        *result = (lhs->toNumber() != rhs->toNumber());
+        *result = (lhs->numberToDouble() != rhs->numberToDouble());
         break;
       default:
         return false;
     }
 
     return true;
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1366,16 +1366,17 @@ class MLimitedTruncate
 
 // A constant js::Value.
 class MConstant : public MNullaryInstruction
 {
     struct Payload {
         union {
             bool b;
             int32_t i32;
+            int64_t i64;
             float f;
             double d;
             JSString* str;
             JS::Symbol* sym;
             JSObject* obj;
             uint64_t asBits;
         };
         Payload() : asBits(0) {}
@@ -1391,22 +1392,24 @@ class MConstant : public MNullaryInstruc
 #else
     void assertInitializedPayload() const {}
 #endif
 
   protected:
     MConstant(const Value& v, CompilerConstraintList* constraints);
     explicit MConstant(JSObject* obj);
     explicit MConstant(float f);
+    explicit MConstant(int64_t i);
 
   public:
     INSTRUCTION_HEADER(Constant)
     static MConstant* New(TempAllocator& alloc, const Value& v,
                           CompilerConstraintList* constraints = nullptr);
     static MConstant* NewFloat32(TempAllocator& alloc, double d);
+    static MConstant* NewInt64(TempAllocator& alloc, int64_t i);
     static MConstant* NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type);
     static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
 
     // Try to convert this constant to boolean, similar to js::ToBoolean.
     // Returns false if the type is MIRType_Magic*.
     bool valueToBoolean(bool* res) const;
 
     // Like valueToBoolean, but returns the result directly instead of using
@@ -1453,16 +1456,20 @@ class MConstant : public MNullaryInstruc
     bool toBoolean() const {
         MOZ_ASSERT(type() == MIRType_Boolean);
         return payload_.b;
     }
     int32_t toInt32() const {
         MOZ_ASSERT(type() == MIRType_Int32);
         return payload_.i32;
     }
+    int64_t toInt64() const {
+        MOZ_ASSERT(type() == MIRType_Int64);
+        return payload_.i64;
+    }
     bool isInt32(int32_t i) const {
         return type() == MIRType_Int32 && payload_.i32 == i;
     }
     double toDouble() const {
         MOZ_ASSERT(type() == MIRType_Double);
         return payload_.d;
     }
     float toFloat32() const {
@@ -1483,25 +1490,25 @@ class MConstant : public MNullaryInstruc
     }
     JSObject* toObjectOrNull() const {
         if (type() == MIRType_Object)
             return payload_.obj;
         MOZ_ASSERT(type() == MIRType_Null);
         return nullptr;
     }
 
-    bool isNumber() const {
-        return IsNumberType(type());
-    }
-    double toNumber() const {
+    bool isTypeRepresentableAsDouble() const {
+        return IsTypeRepresentableAsDouble(type());
+    }
+    double numberToDouble() const {
+        MOZ_ASSERT(isTypeRepresentableAsDouble());
         if (type() == MIRType_Int32)
             return toInt32();
         if (type() == MIRType_Double)
             return toDouble();
-        MOZ_ASSERT(type() == MIRType_Float32);
         return toFloat32();
     }
 
     // Convert this constant to a js::Value. Float32 constants will be stored
     // as DoubleValue and NaNs are canonicalized. Callers must be careful: not
     // all constants can be represented by js::Value (wasm supports int64).
     Value toJSValue() const;
 };
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -193,22 +193,22 @@ RangeAnalysis::addBetaNodes()
         if (branch_dir == FALSE_BRANCH) {
             jsop = NegateCompareOp(jsop);
             conservativeLower = GenericNaN();
             conservativeUpper = GenericNaN();
         }
 
         MConstant* leftConst = left->maybeConstantValue();
         MConstant* rightConst = right->maybeConstantValue();
-        if (leftConst && leftConst->isNumber()) {
-            bound = leftConst->toNumber();
+        if (leftConst && leftConst->isTypeRepresentableAsDouble()) {
+            bound = leftConst->numberToDouble();
             val = right;
             jsop = ReverseCompareOp(jsop);
-        } else if (rightConst && rightConst->isNumber()) {
-            bound = rightConst->toNumber();
+        } else if (rightConst && rightConst->isTypeRepresentableAsDouble()) {
+            bound = rightConst->numberToDouble();
             val = left;
         } else if (left->type() == MIRType_Int32 && right->type() == MIRType_Int32) {
             MDefinition* smaller = nullptr;
             MDefinition* greater = nullptr;
             if (jsop == JSOP_LT) {
                 smaller = left;
                 greater = right;
             } else if (jsop == JSOP_GT) {
@@ -1286,18 +1286,18 @@ MBeta::computeRange(TempAllocator& alloc
     } else {
         setRange(range);
     }
 }
 
 void
 MConstant::computeRange(TempAllocator& alloc)
 {
-    if (isNumber()) {
-        double d = toNumber();
+    if (isTypeRepresentableAsDouble()) {
+        double d = numberToDouble();
         setRange(Range::NewDoubleSingletonRange(alloc, d));
     } else if (type() == MIRType_Boolean) {
         bool b = toBoolean();
         setRange(Range::NewInt32Range(alloc, b, b));
     }
 }
 
 void
@@ -2411,17 +2411,17 @@ MConstant::needTruncation(TruncateKind k
 }
 
 void
 MConstant::truncate()
 {
     MOZ_ASSERT(needTruncation(Truncate));
 
     // Truncate the double to int, since all uses truncates it.
-    int32_t res = ToInt32(toNumber());
+    int32_t res = ToInt32(numberToDouble());
     payload_.asBits = 0;
     payload_.i32 = res;
     setResultType(MIRType_Int32);
     if (range())
         range()->setInt32(res, res);
 }
 
 bool
--- a/js/src/jit/shared/CodeGenerator-shared-inl.h
+++ b/js/src/jit/shared/CodeGenerator-shared-inl.h
@@ -23,17 +23,17 @@ ToInt32(const LAllocation* a)
     if (a->isConstantIndex())
         return a->toConstantIndex()->index();
     MOZ_CRASH("this is not a constant!");
 }
 
 static inline double
 ToDouble(const LAllocation* a)
 {
-    return a->toConstant()->toNumber();
+    return a->toConstant()->numberToDouble();
 }
 
 static inline Register
 ToRegister(const LAllocation& a)
 {
     MOZ_ASSERT(a.isGeneralReg());
     return a.toGeneralReg()->reg();
 }
--- a/js/src/jsapi-tests/testJitDCEinGVN.cpp
+++ b/js/src/jsapi-tests/testJitDCEinGVN.cpp
@@ -131,13 +131,13 @@ BEGIN_TEST(testJitDCEinGVN_phi)
     MReturn* ret = MReturn::New(func.alloc, y);
     joinBlock->end(ret);
 
     if (!func.runGVN())
         return false;
 
     // c1 should be deleted.
     for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
-        CHECK(!ins->isConstant() || (ins->toConstant()->toNumber() != 1.0));
+        CHECK(!ins->isConstant() || (ins->toConstant()->numberToDouble() != 1.0));
     }
     return true;
 }
 END_TEST(testJitDCEinGVN_phi)
--- a/js/src/jsapi-tests/testJitFoldsTo.cpp
+++ b/js/src/jsapi-tests/testJitFoldsTo.cpp
@@ -37,17 +37,17 @@ BEGIN_TEST(testJitFoldsTo_DivReciprocal)
     if (!func.runGVN())
         return false;
 
     // Test that the div got folded to p * 0.25.
     MDefinition* op = ret->getOperand(0);
     CHECK(op->isMul());
     CHECK(op->getOperand(0) == left);
     CHECK(op->getOperand(1)->isConstant());
-    CHECK(op->getOperand(1)->toConstant()->toNumber() == 0.25);
+    CHECK(op->getOperand(1)->toConstant()->numberToDouble() == 0.25);
     return true;
 }
 END_TEST(testJitFoldsTo_DivReciprocal)
 
 BEGIN_TEST(testJitFoldsTo_NoDivReciprocal)
 {
     MinimalFunc func;
     MBasicBlock* block = func.createEntryBlock();
@@ -224,17 +224,17 @@ BEGIN_TEST(testJitFoldsTo_UnsignedDiv)
     MReturn* ret = MReturn::New(func.alloc, div);
     block->end(ret);
 
     if (!func.runGVN())
         return false;
 
     // Test that the div got folded to 0.
     MConstant* op = ret->getOperand(0)->toConstant();
-    CHECK(mozilla::NumbersAreIdentical(op->toNumber(), 0.0));
+    CHECK(mozilla::NumbersAreIdentical(op->numberToDouble(), 0.0));
     return true;
 }
 END_TEST(testJitFoldsTo_UnsignedDiv)
 
 BEGIN_TEST(testJitFoldsTo_UnsignedMod)
 {
     MinimalFunc func;
     MBasicBlock* block = func.createEntryBlock();
@@ -249,12 +249,12 @@ BEGIN_TEST(testJitFoldsTo_UnsignedMod)
     MReturn* ret = MReturn::New(func.alloc, mod);
     block->end(ret);
 
     if (!func.runGVN())
         return false;
 
     // Test that the mod got folded to 1.
     MConstant* op = ret->getOperand(0)->toConstant();
-    CHECK(mozilla::NumbersAreIdentical(op->toNumber(), 1.0));
+    CHECK(mozilla::NumbersAreIdentical(op->numberToDouble(), 1.0));
     return true;
 }
 END_TEST(testJitFoldsTo_UnsignedMod)