Bug 1246658 part 1 - Refactor MDefinition::constantValue and friends. r=bbouvier
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 12 Feb 2016 08:58:26 +0100
changeset 284128 6cbce3cad8b7
parent 284127 8ceeb0696aa4
child 284129 dae4acefe53b
push id29998
push userphilringnalda@gmail.com
push date2016-02-14 03:19 +0000
treeherdermozilla-central@e355cacefc88 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
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 1 - Refactor MDefinition::constantValue and friends. r=bbouvier
js/src/jit/AlignmentMaskAnalysis.cpp
js/src/jit/EffectiveAddressAnalysis.cpp
js/src/jit/IonAnalysis.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/Lowering.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/RangeAnalysis.cpp
js/src/jit/ScalarReplacement.cpp
js/src/jit/arm/Lowering-arm.cpp
--- a/js/src/jit/AlignmentMaskAnalysis.cpp
+++ b/js/src/jit/AlignmentMaskAnalysis.cpp
@@ -35,35 +35,37 @@ AnalyzeAsmHeapAddress(MDefinition* ptr, 
     // EffectiveAddressAnalysis pass.
     //
     // Putting the add on the outside might seem like it exposes other users of
     // the expression to the possibility of i32 overflow, if we aren't in asm.js
     // and they aren't naturally truncating. However, since we use MAdd::NewAsmJS
     // with MIRType_Int32, we make sure that the value is truncated, just as it
     // would be by the MBitAnd.
 
+    MOZ_ASSERT(IsCompilingAsmJS());
+
     if (!ptr->isBitAnd())
         return;
 
     MDefinition* lhs = ptr->toBitAnd()->getOperand(0);
     MDefinition* rhs = ptr->toBitAnd()->getOperand(1);
-    if (lhs->isConstantValue())
+    if (lhs->isConstant())
         mozilla::Swap(lhs, rhs);
-    if (!lhs->isAdd() || !rhs->isConstantValue())
+    if (!lhs->isAdd() || !rhs->isConstant())
         return;
 
     MDefinition* op0 = lhs->toAdd()->getOperand(0);
     MDefinition* op1 = lhs->toAdd()->getOperand(1);
-    if (op0->isConstantValue())
+    if (op0->isConstant())
         mozilla::Swap(op0, op1);
-    if (!op1->isConstantValue())
+    if (!op1->isConstant())
         return;
 
-    uint32_t i = op1->constantValue().toInt32();
-    uint32_t m = rhs->constantValue().toInt32();
+    uint32_t i = op1->toConstant()->value().toInt32();
+    uint32_t m = rhs->toConstant()->value().toInt32();
     if (!IsAlignmentMask(m) || (i & m) != i)
         return;
 
     // The pattern was matched! Produce the replacement expression.
     MInstruction* and_ = MBitAnd::NewAsmJS(graph.alloc(), op0, rhs);
     ptr->block()->insertBefore(ptr->toBitAnd(), and_);
     MInstruction* add = MAdd::NewAsmJS(graph.alloc(), and_, op1, MIRType_Int32);
     ptr->block()->insertBefore(ptr->toBitAnd(), add);
--- a/js/src/jit/EffectiveAddressAnalysis.cpp
+++ b/js/src/jit/EffectiveAddressAnalysis.cpp
@@ -18,25 +18,25 @@ AnalyzeLsh(TempAllocator& alloc, MLsh* l
         return;
 
     if (lsh->isRecoveredOnBailout())
         return;
 
     MDefinition* index = lsh->lhs();
     MOZ_ASSERT(index->type() == MIRType_Int32);
 
-    MDefinition* shift = lsh->rhs();
-    if (!shift->isConstantValue())
+    MConstant* shiftValue = lsh->rhs()->maybeConstantValue();
+    if (!shiftValue)
         return;
 
-    Value shiftValue = shift->constantValue();
-    if (!shiftValue.isInt32() || !IsShiftInScaleRange(shiftValue.toInt32()))
+    Value shiftv = shiftValue->value();
+    if (!shiftv.isInt32() || !IsShiftInScaleRange(shiftv.toInt32()))
         return;
 
-    Scale scale = ShiftToScale(shiftValue.toInt32());
+    Scale scale = ShiftToScale(shiftv.toInt32());
 
     int32_t displacement = 0;
     MInstruction* last = lsh;
     MDefinition* base = nullptr;
     while (true) {
         if (!last->hasOneUse())
             break;
 
@@ -45,18 +45,18 @@ AnalyzeLsh(TempAllocator& alloc, MLsh* l
             break;
 
         MAdd* add = use->consumer()->toDefinition()->toAdd();
         if (add->specialization() != MIRType_Int32 || !add->isTruncated())
             break;
 
         MDefinition* other = add->getOperand(1 - add->indexOf(*use));
 
-        if (other->isConstantValue()) {
-            displacement += other->constantValue().toInt32();
+        if (MConstant* otherConst = other->maybeConstantValue()) {
+            displacement += otherConst->value().toInt32();
         } else {
             if (base)
                 break;
             base = other;
         }
 
         last = add;
         if (last->isRecoveredOnBailout())
@@ -75,21 +75,22 @@ AnalyzeLsh(TempAllocator& alloc, MLsh* l
         if (!use->consumer()->isDefinition() || !use->consumer()->toDefinition()->isBitAnd())
             return;
 
         MBitAnd* bitAnd = use->consumer()->toDefinition()->toBitAnd();
         if (bitAnd->isRecoveredOnBailout())
             return;
 
         MDefinition* other = bitAnd->getOperand(1 - bitAnd->indexOf(*use));
-        if (!other->isConstantValue() || !other->constantValue().isInt32())
+        MConstant* otherConst = other->maybeConstantValue();
+        if (!otherConst || otherConst->type() != MIRType_Int32)
             return;
 
         uint32_t bitsClearedByShift = elemSize - 1;
-        uint32_t bitsClearedByMask = ~uint32_t(other->constantValue().toInt32());
+        uint32_t bitsClearedByMask = ~uint32_t(otherConst->value().toInt32());
         if ((bitsClearedByShift & bitsClearedByMask) != bitsClearedByMask)
             return;
 
         bitAnd->replaceAllUsesWith(last);
         return;
     }
 
     if (base->isRecoveredOnBailout())
@@ -131,38 +132,38 @@ EffectiveAddressAnalysis::tryAddDisplace
 }
 
 template<typename MAsmJSHeapAccessType>
 void
 EffectiveAddressAnalysis::analyzeAsmHeapAccess(MAsmJSHeapAccessType* ins)
 {
     MDefinition* ptr = ins->ptr();
 
-    if (ptr->isConstantValue()) {
+    if (ptr->isConstant()) {
         // Look for heap[i] where i is a constant offset, and fold the offset.
         // By doing the folding now, we simplify the task of codegen; the offset
         // is always the address mode immediate. This also allows it to avoid
         // a situation where the sum of a constant pointer value and a non-zero
         // offset doesn't actually fit into the address mode immediate.
-        int32_t imm = ptr->constantValue().toInt32();
+        int32_t imm = ptr->toConstant()->value().toInt32();
         if (imm != 0 && tryAddDisplacement(ins, imm)) {
             MInstruction* zero = MConstant::New(graph_.alloc(), Int32Value(0));
             ins->block()->insertBefore(ins, zero);
             ins->replacePtr(zero);
         }
     } else if (ptr->isAdd()) {
         // Look for heap[a+i] where i is a constant offset, and fold the offset.
         // Alignment masks have already been moved out of the way by the
         // Alignment Mask Analysis pass.
         MDefinition* op0 = ptr->toAdd()->getOperand(0);
         MDefinition* op1 = ptr->toAdd()->getOperand(1);
-        if (op0->isConstantValue())
+        if (op0->isConstant())
             mozilla::Swap(op0, op1);
-        if (op1->isConstantValue()) {
-            int32_t imm = op1->constantValue().toInt32();
+        if (op1->isConstant()) {
+            int32_t imm = op1->toConstant()->value().toInt32();
             if (tryAddDisplacement(ins, imm))
                 ins->replacePtr(op0);
         }
     }
 }
 
 // This analysis converts patterns of the form:
 //   truncate(x + (y << {0,1,2,3}))
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -741,31 +741,31 @@ MaybeFoldConditionBlock(MIRGraph& graph,
 
     // If either trueBranch or falseBranch just computes a constant for the
     // test, determine the block that branch will end up jumping to and eliminate
     // the branch. Otherwise, change the end of the block to a test that jumps
     // directly to successors of testBlock, rather than to testBlock itself.
 
     MBasicBlock* trueTarget = trueBranch;
     if (BlockComputesConstant(trueBranch, trueResult)) {
-        trueTarget = trueResult->constantToBoolean()
+        trueTarget = trueResult->toConstant()->valueToBoolean()
                      ? finalTest->ifTrue()
                      : finalTest->ifFalse();
         phiBlock->removePredecessor(trueBranch);
         graph.removeBlock(trueBranch);
     } else if (initialTest->input() == trueResult) {
         UpdateGotoSuccessor(graph.alloc(), trueBranch, finalTest->ifTrue(), testBlock);
     } else {
         UpdateTestSuccessors(graph.alloc(), trueBranch, trueResult,
                              finalTest->ifTrue(), finalTest->ifFalse(), testBlock);
     }
 
     MBasicBlock* falseTarget = falseBranch;
     if (BlockComputesConstant(falseBranch, falseResult)) {
-        falseTarget = falseResult->constantToBoolean()
+        falseTarget = falseResult->toConstant()->valueToBoolean()
                       ? finalTest->ifTrue()
                       : finalTest->ifFalse();
         phiBlock->removePredecessor(falseBranch);
         graph.removeBlock(falseBranch);
     } else if (initialTest->input() == falseResult) {
         UpdateGotoSuccessor(graph.alloc(), falseBranch, finalTest->ifFalse(), testBlock);
     } else {
         UpdateTestSuccessors(graph.alloc(), falseBranch, falseResult,
@@ -2700,37 +2700,40 @@ SimpleLinearSum
 jit::ExtractLinearSum(MDefinition* ins)
 {
     if (ins->isBeta())
         ins = ins->getOperand(0);
 
     if (ins->type() != MIRType_Int32)
         return SimpleLinearSum(ins, 0);
 
-    if (ins->isConstantValue()) {
-        const Value& v = ins->constantValue();
+    if (ins->isConstant()) {
+        const Value& v = ins->toConstant()->value();
         MOZ_ASSERT(v.isInt32());
         return SimpleLinearSum(nullptr, v.toInt32());
-    } else if (ins->isAdd() || ins->isSub()) {
+    }
+
+    if (ins->isAdd() || ins->isSub()) {
         MDefinition* lhs = ins->getOperand(0);
         MDefinition* rhs = ins->getOperand(1);
         if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
             SimpleLinearSum lsum = ExtractLinearSum(lhs);
             SimpleLinearSum rsum = ExtractLinearSum(rhs);
 
             if (lsum.term && rsum.term)
                 return SimpleLinearSum(ins, 0);
 
             // Check if this is of the form <SUM> + n, n + <SUM> or <SUM> - n.
             if (ins->isAdd()) {
                 int32_t constant;
                 if (!SafeAdd(lsum.constant, rsum.constant, &constant))
                     return SimpleLinearSum(ins, 0);
                 return SimpleLinearSum(lsum.term ? lsum.term : rsum.term, constant);
-            } else if (lsum.term) {
+            }
+            if (lsum.term) {
                 int32_t constant;
                 if (!SafeSub(lsum.constant, rsum.constant, &constant))
                     return SimpleLinearSum(ins, 0);
                 return SimpleLinearSum(lsum.term, constant);
             }
         }
     }
 
@@ -3317,18 +3320,18 @@ LinearSum::add(SimpleLinearSum other, in
 bool
 LinearSum::add(MDefinition* term, int32_t scale)
 {
     MOZ_ASSERT(term);
 
     if (scale == 0)
         return true;
 
-    if (term->isConstantValue()) {
-        int32_t constant = term->constantValue().toInt32();
+    if (MConstant* termConst = term->maybeConstantValue()) {
+        int32_t constant = termConst->value().toInt32();
         if (!SafeMul(constant, scale, &constant))
             return false;
         return add(constant);
     }
 
     for (size_t i = 0; i < terms_.length(); i++) {
         if (term == terms_[i].term) {
             if (!SafeAdd(scale, terms_[i].scale, &terms_[i].scale))
@@ -3390,17 +3393,17 @@ LinearSum::dump() const
 
 MDefinition*
 jit::ConvertLinearSum(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum, bool convertConstant)
 {
     MDefinition* def = nullptr;
 
     for (size_t i = 0; i < sum.numTerms(); i++) {
         LinearTerm term = sum.term(i);
-        MOZ_ASSERT(!term.term->isConstantValue());
+        MOZ_ASSERT(!term.term->isConstant());
         if (term.scale == 1) {
             if (def) {
                 def = MAdd::New(alloc, def, term.term);
                 def->toAdd()->setInt32Specialization();
                 block->insertAtEnd(def->toInstruction());
                 def->computeRange(alloc);
             } else {
                 def = term.term;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2552,18 +2552,18 @@ IonBuilder::processDoWhileCondEnd(CFGSta
 
     // Pop the last value, and create the successor block.
     MDefinition* vins = current->pop();
     MBasicBlock* successor = newBlock(current, GetNextPc(pc), loopDepth_ - 1);
     if (!successor)
         return ControlStatus_Error;
 
     // Test for do {} while(false) and don't create a loop in that case.
-    if (vins->isConstantValue() && !vins->constantValue().isMagic()) {
-        if (!vins->constantToBoolean()) {
+    if (MConstant* vinsConst = vins->maybeConstantValue()) {
+        if (!IsMagicType(vinsConst->type()) && !vinsConst->valueToBoolean()) {
             current->end(MGoto::New(alloc(), successor));
             current = nullptr;
 
             state.loop.successor = successor;
             return processBrokenLoop(state);
         }
     }
 
@@ -3666,30 +3666,30 @@ IonBuilder::improveTypesAtCompare(MCompa
 {
     if (ins->compareType() == MCompare::Compare_Undefined ||
         ins->compareType() == MCompare::Compare_Null)
     {
         return improveTypesAtNullOrUndefinedCompare(ins, trueBranch, test);
     }
 
     if ((ins->lhs()->isTypeOf() || ins->rhs()->isTypeOf()) &&
-        (ins->lhs()->isConstantValue() || ins->rhs()->isConstantValue()))
+        (ins->lhs()->isConstant() || ins->rhs()->isConstant()))
     {
         return improveTypesAtTypeOfCompare(ins, trueBranch, test);
     }
 
     return true;
 }
 
 bool
 IonBuilder::improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* test)
 {
     MTypeOf* typeOf = ins->lhs()->isTypeOf() ? ins->lhs()->toTypeOf() : ins->rhs()->toTypeOf();
-    const Value* constant =
-        ins->lhs()->isConstant() ? ins->lhs()->constantVp() : ins->rhs()->constantVp();
+    MConstant* constantDef = ins->lhs()->isConstant() ? ins->lhs()->toConstant() : ins->rhs()->toConstant();
+    const Value* constant = constantDef->vp();
 
     if (!constant->isString())
         return true;
 
     bool equal = ins->jsop() == JSOP_EQ || ins->jsop() == JSOP_STRICTEQ;
     bool notEqual = ins->jsop() == JSOP_NE || ins->jsop() == JSOP_STRICTNE;
 
     if (notEqual)
@@ -4861,18 +4861,18 @@ IonBuilder::arithTrySharedStub(bool* emi
     // The actual jsop 'jsop_pos' is not supported yet.
     if (actualOp == JSOP_POS)
         return true;
 
     MInstruction* stub = nullptr;
     switch (actualOp) {
       case JSOP_NEG:
       case JSOP_BITNOT:
-        MOZ_ASSERT_IF(op == JSOP_MUL, left->isConstantValue() &&
-                                      left->constantValue().toInt32() == -1);
+        MOZ_ASSERT_IF(op == JSOP_MUL,
+                      left->maybeConstantValue() && left->maybeConstantValue()->value().toInt32() == -1);
         MOZ_ASSERT_IF(op != JSOP_MUL, !left);
 
         stub = MUnarySharedStub::New(alloc(), right);
         break;
       case JSOP_ADD:
       case JSOP_SUB:
       case JSOP_MUL:
       case JSOP_DIV:
@@ -6873,20 +6873,20 @@ IonBuilder::jsop_eval(uint32_t argc)
         if (!jsop_newtarget())
             return false;
         MDefinition* newTargetValue = current->pop();
 
         // Try to pattern match 'eval(v + "()")'. In this case v is likely a
         // name on the scope chain and the eval is performing a call on that
         // value. Use a dynamic scope chain lookup rather than a full eval.
         if (string->isConcat() &&
-            string->getOperand(1)->isConstantValue() &&
-            string->getOperand(1)->constantValue().isString())
+            string->getOperand(1)->type() == MIRType_String &&
+            string->getOperand(1)->maybeConstantValue())
         {
-            JSAtom* atom = &string->getOperand(1)->constantValue().toString()->asAtom();
+            JSAtom* atom = &string->getOperand(1)->maybeConstantValue()->value().toString()->asAtom();
 
             if (StringEqualsAscii(atom, "()")) {
                 MDefinition* name = string->getOperand(0);
                 MInstruction* dynamicName = MGetDynamicName::New(alloc(), scopeChain, name);
                 current->add(dynamicName);
 
                 current->push(dynamicName);
                 current->push(constant(UndefinedValue())); // thisv
@@ -8974,21 +8974,19 @@ IonBuilder::pushDerivedTypedObject(bool*
 bool
 IonBuilder::getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index)
 {
     // If index is a constant string or symbol, try to optimize this GETELEM
     // as a GETPROP.
 
     MOZ_ASSERT(*emitted == false);
 
-    if (!index->isConstantValue())
-        return true;
-
+    MConstant* indexConst = index->maybeConstantValue();
     jsid id;
-    if (!ValueToIdPure(index->constantValue(), &id))
+    if (!indexConst || !ValueToIdPure(indexConst->value(), &id))
         return true;
 
     if (id != IdToTypeId(id))
         return true;
 
     TemporaryTypeSet* types = bytecodeTypes(pc);
 
     trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
@@ -9244,20 +9242,21 @@ IonBuilder::getElemTryArgumentsInlined(b
         return true;
 
     // Emit inlined arguments.
     obj->setImplicitlyUsedUnchecked();
 
     MOZ_ASSERT(!info().argsObjAliasesFormals());
 
     // When the id is constant, we can just return the corresponding inlined argument
-    if (index->isConstantValue() && index->constantValue().isInt32()) {
+    MConstant* indexConst = index->maybeConstantValue();
+    if (indexConst && indexConst->type() == MIRType_Int32) {
         MOZ_ASSERT(inliningDepth_ > 0);
 
-        int32_t id = index->constantValue().toInt32();
+        int32_t id = indexConst->value().toInt32();
         index->setImplicitlyUsedUnchecked();
 
         if (id < (int32_t)inlineCallInfo_->argc() && id >= 0)
             current->push(inlineCallInfo_->getArg(id));
         else
             pushConstant(UndefinedValue());
 
         trackOptimizationSuccess();
@@ -9484,22 +9483,25 @@ IonBuilder::jsop_getelem_dense(MDefiniti
 
 void
 IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
                                        BoundsChecking checking,
                                        MDefinition** index,
                                        MInstruction** length, MInstruction** elements)
 {
     MOZ_ASSERT((index != nullptr) == (elements != nullptr));
+
     JSObject* tarr = nullptr;
 
-    if (obj->isConstantValue() && obj->constantValue().isObject())
-        tarr = &obj->constantValue().toObject();
-    else if (obj->resultTypeSet())
-        tarr = obj->resultTypeSet()->maybeSingleton();
+    if (MConstant* objConst = obj->maybeConstantValue()) {
+        if (objConst->type() == MIRType_Object)
+            tarr = &objConst->value().toObject();
+    } else if (TemporaryTypeSet* types = obj->resultTypeSet()) {
+        tarr = types->maybeSingleton();
+    }
 
     if (tarr) {
         SharedMem<void*> data = tarr->as<TypedArrayObject>().viewDataEither();
         // Bug 979449 - Optimistically embed the elements and use TI to
         //              invalidate if we move them.
         bool isTenured = !tarr->runtimeFromMainThread()->gc.nursery.isInside(data);
         if (isTenured && tarr->isSingleton()) {
             // The 'data' pointer of TypedArrayObject can change in rare circumstances
@@ -9546,28 +9548,30 @@ IonBuilder::convertShiftToMaskForStaticT
     trackOptimizationOutcome(TrackedOutcome::StaticTypedArrayCantComputeMask);
 
     // No shifting is necessary if the typed array has single byte elements.
     if (TypedArrayShift(viewType) == 0)
         return id;
 
     // If the index is an already shifted constant, undo the shift to get the
     // absolute offset being accessed.
-    if (id->isConstantValue() && id->constantValue().isInt32()) {
-        int32_t index = id->constantValue().toInt32();
-        MConstant* offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType)));
-        current->add(offset);
-        return offset;
+    if (MConstant* idConst = id->maybeConstantValue()) {
+        if (idConst->type() == MIRType_Int32) {
+            int32_t index = idConst->value().toInt32();
+            MConstant* offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType)));
+            current->add(offset);
+            return offset;
+        }
     }
 
     if (!id->isRsh() || id->isEffectful())
         return nullptr;
-    if (!id->getOperand(1)->isConstantValue())
+    if (!id->getOperand(1)->maybeConstantValue())
         return nullptr;
-    const Value& value = id->getOperand(1)->constantValue();
+    const Value& value = id->getOperand(1)->maybeConstantValue()->value();
     if (!value.isInt32() || uint32_t(value.toInt32()) != TypedArrayShift(viewType))
         return nullptr;
 
     // Instead of shifting, mask off the low bits of the index so that
     // a non-scaled access on the typed array can be performed.
     MConstant* mask = MConstant::New(alloc(), Int32Value(~((1 << value.toInt32()) - 1)));
     MBitAnd* ptr = MBitAnd::New(alloc(), id->getOperand(0), mask);
 
@@ -13393,17 +13397,17 @@ bool
 IonBuilder::inTryFold(bool* emitted, MDefinition* obj, MDefinition* id)
 {
     // Fold |id in obj| to |false|, if we know the object (or an object on its
     // prototype chain) does not have this property.
 
     MOZ_ASSERT(!*emitted);
 
     jsid propId;
-    if (!id->isConstantValue() || !ValueToIdPure(id->constantValue(), &propId))
+    if (!id->maybeConstantValue() || !ValueToIdPure(id->maybeConstantValue()->value(), &propId))
         return true;
 
     if (propId != IdToTypeId(propId))
         return true;
 
     TemporaryTypeSet* types = obj->resultTypeSet();
     if (!types || types->unknownObject())
         return true;
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -690,17 +690,17 @@ LIRGenerator::visitCallDirectEval(MCallD
 }
 
 static JSOp
 ReorderComparison(JSOp op, MDefinition** lhsp, MDefinition** rhsp)
 {
     MDefinition* lhs = *lhsp;
     MDefinition* rhs = *rhsp;
 
-    if (lhs->isConstantValue()) {
+    if (lhs->maybeConstantValue()) {
         *rhsp = lhs;
         *lhsp = rhs;
         return ReverseCompareOp(op);
     }
     return op;
 }
 
 void
@@ -710,18 +710,18 @@ LIRGenerator::visitTest(MTest* test)
     MBasicBlock* ifTrue = test->ifTrue();
     MBasicBlock* ifFalse = test->ifFalse();
 
     // String is converted to length of string in the type analysis phase (see
     // TestPolicy).
     MOZ_ASSERT(opd->type() != MIRType_String);
 
     // Testing a constant.
-    if (opd->isConstantValue() && !opd->constantValue().isMagic()) {
-        bool result = opd->constantToBoolean();
+    if (opd->maybeConstantValue() && !opd->maybeConstantValue()->value().isMagic()) {
+        bool result = opd->maybeConstantValue()->valueToBoolean();
         add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
         return;
     }
 
     if (opd->type() == MIRType_Value) {
         LDefinition temp0, temp1;
         if (test->operandMightEmulateUndefined()) {
             temp0 = temp();
@@ -1589,35 +1589,35 @@ LIRGenerator::visitMul(MMul* ins)
     MOZ_ASSERT(lhs->type() == rhs->type());
 
     if (ins->specialization() == MIRType_Int32) {
         MOZ_ASSERT(lhs->type() == MIRType_Int32);
         ReorderCommutative(&lhs, &rhs, ins);
 
         // If our RHS is a constant -1 and we don't have to worry about
         // overflow, we can optimize to an LNegI.
-        if (!ins->fallible() && rhs->isConstantValue() && rhs->constantValue() == Int32Value(-1))
+        if (!ins->fallible() && rhs->isConstant() && rhs->toConstant()->value().toInt32() == -1)
             defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(lhs)), ins, 0);
         else
             lowerMulI(ins, lhs, rhs);
     } else if (ins->specialization() == MIRType_Double) {
         MOZ_ASSERT(lhs->type() == MIRType_Double);
         ReorderCommutative(&lhs, &rhs, ins);
 
         // If our RHS is a constant -1.0, we can optimize to an LNegD.
-        if (rhs->isConstantValue() && rhs->constantValue() == DoubleValue(-1.0))
+        if (rhs->isConstant() && rhs->toConstant()->value().toDouble() == -1.0)
             defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
         else
             lowerForFPU(new(alloc()) LMathD(JSOP_MUL), ins, lhs, rhs);
     } else if (ins->specialization() == MIRType_Float32) {
         MOZ_ASSERT(lhs->type() == MIRType_Float32);
         ReorderCommutative(&lhs, &rhs, ins);
 
         // We apply the same optimizations as for doubles
-        if (rhs->isConstantValue() && rhs->constantValue() == Float32Value(-1.0f))
+        if (rhs->isConstant() && rhs->toConstant()->value().toDouble() == -1.0)
             defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
         else
             lowerForFPU(new(alloc()) LMathF(JSOP_MUL), ins, lhs, rhs);
     } else {
         lowerBinaryV(JSOP_MUL, ins);
     }
 }
 
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -413,36 +413,36 @@ IonBuilder::inlineArray(CallInfo& callIn
                     return InliningStatus_NotInlined;
                 }
             }
         }
     }
 
     // A single integer argument denotes initial length.
     if (callInfo.argc() == 1) {
-        if (callInfo.getArg(0)->type() != MIRType_Int32)
+        MDefinition* arg = callInfo.getArg(0);
+        if (arg->type() != MIRType_Int32)
             return InliningStatus_NotInlined;
 
-        MDefinition* arg = callInfo.getArg(0);
-        if (!arg->isConstantValue()) {
+        if (!arg->isConstant()) {
             callInfo.setImplicitlyUsedUnchecked();
             MNewArrayDynamicLength* ins =
                 MNewArrayDynamicLength::New(alloc(), constraints(), templateObject,
                                             templateObject->group()->initialHeap(constraints()),
                                             arg);
             current->add(ins);
             current->push(ins);
             return InliningStatus_Inlined;
         }
 
         // The next several checks all may fail due to range conditions.
         trackOptimizationOutcome(TrackedOutcome::ArrayRange);
 
         // Negative lengths generate a RangeError, unhandled by the inline path.
-        initLength = arg->constantValue().toInt32();
+        initLength = arg->toConstant()->value().toInt32();
         if (initLength > NativeObject::MAX_DENSE_ELEMENTS_COUNT)
             return InliningStatus_NotInlined;
         MOZ_ASSERT(initLength <= INT32_MAX);
 
         // Make sure initLength matches the template object's length. This is
         // not guaranteed to be the case, for instance if we're inlining the
         // MConstant may come from an outer script.
         if (initLength != GetAnyBoxedOrUnboxedArrayLength(templateObject))
@@ -1259,18 +1259,18 @@ IonBuilder::inlineMathPowHelper(MDefinit
     if (!IsNumberType(powerType))
         return InliningStatus_NotInlined;
 
     MDefinition* base = lhs;
     MDefinition* power = rhs;
     MDefinition* output = nullptr;
 
     // Optimize some constant powers.
-    if (rhs->isConstantValue() && rhs->constantValue().isNumber()) {
-        double pow = rhs->constantValue().toNumber();
+    if (rhs->isConstant()) {
+        double pow = rhs->toConstant()->value().toNumber();
 
         // 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;
         }
 
@@ -1465,18 +1465,18 @@ IonBuilder::inlineMathMinMax(CallInfo& c
           case MIRType_Int32:
             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->isConstantValue()) {
-                double cte = arg->constantValue().toDouble();
+            if (arg->isConstant()) {
+                double cte = arg->toConstant()->value().toDouble();
                 // min(int32, cte >= INT32_MAX) = int32
                 if (cte >= INT32_MAX && !max)
                     break;
                 // max(int32, cte <= INT32_MIN) = int32
                 if (cte <= INT32_MIN && max)
                     break;
             }
 
@@ -1734,23 +1734,23 @@ IonBuilder::inlineStrCharCodeAt(CallInfo
     current->add(charCode);
     current->push(charCode);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineConstantCharCodeAt(CallInfo& callInfo)
 {
-    if (!callInfo.thisArg()->isConstantValue() || !callInfo.getArg(0)->isConstantValue()) {
+    if (!callInfo.thisArg()->maybeConstantValue() || !callInfo.getArg(0)->maybeConstantValue()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
         return InliningStatus_NotInlined;
     }
 
-    const js::Value* strval = callInfo.thisArg()->constantVp();
-    const js::Value* idxval  = callInfo.getArg(0)->constantVp();
+    const js::Value* strval = callInfo.thisArg()->maybeConstantValue()->vp();
+    const js::Value* idxval = callInfo.getArg(0)->maybeConstantValue()->vp();
 
     if (!strval->isString() || !idxval->isInt32())
         return InliningStatus_NotInlined;
 
     JSString* str = strval->toString();
     if (!str->isLinear()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
         return InliningStatus_NotInlined;
@@ -2409,19 +2409,19 @@ IonBuilder::inlineUnsafeSetReservedSlot(
         return InliningStatus_NotInlined;
     if (callInfo.getArg(0)->type() != MIRType_Object)
         return InliningStatus_NotInlined;
     if (callInfo.getArg(1)->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
 
     // Don't inline if we don't have a constant slot.
     MDefinition* arg = callInfo.getArg(1);
-    if (!arg->isConstantValue())
+    if (!arg->isConstant())
         return InliningStatus_NotInlined;
-    uint32_t slot = arg->constantValue().toPrivateUint32();
+    uint32_t slot = arg->toConstant()->value().toPrivateUint32();
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MStoreFixedSlot* store = MStoreFixedSlot::New(alloc(), callInfo.getArg(0), slot, callInfo.getArg(2));
     current->add(store);
     current->push(store);
 
     if (NeedsPostBarrier(callInfo.getArg(2)))
@@ -2439,19 +2439,19 @@ IonBuilder::inlineUnsafeGetReservedSlot(
     }
     if (callInfo.getArg(0)->type() != MIRType_Object)
         return InliningStatus_NotInlined;
     if (callInfo.getArg(1)->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
 
     // Don't inline if we don't have a constant slot.
     MDefinition* arg = callInfo.getArg(1);
-    if (!arg->isConstantValue())
+    if (!arg->isConstant())
         return InliningStatus_NotInlined;
-    uint32_t slot = arg->constantValue().toPrivateUint32();
+    uint32_t slot = arg->toConstant()->value().toPrivateUint32();
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), callInfo.getArg(0), slot);
     current->add(load);
     current->push(load);
     if (knownValueType != MIRType_Value) {
         // We know what type we have in this slot.  Assert that this is in fact
@@ -2627,19 +2627,19 @@ IonBuilder::InliningStatus
 IonBuilder::inlineAssertFloat32(CallInfo& callInfo)
 {
     if (callInfo.argc() != 2)
         return InliningStatus_NotInlined;
 
     MDefinition* secondArg = callInfo.getArg(1);
 
     MOZ_ASSERT(secondArg->type() == MIRType_Boolean);
-    MOZ_ASSERT(secondArg->isConstantValue());
-
-    bool mustBeFloat32 = secondArg->constantValue().toBoolean();
+    MOZ_ASSERT(secondArg->isConstant());
+
+    bool mustBeFloat32 = secondArg->toConstant()->value().toBoolean();
     current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32));
 
     MConstant* undefined = MConstant::New(alloc(), UndefinedValue());
     current->add(undefined);
     current->push(undefined);
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
@@ -2657,19 +2657,19 @@ IonBuilder::inlineAssertRecoveredOnBailo
         current->push(constant(UndefinedValue()));
         callInfo.setImplicitlyUsedUnchecked();
         return InliningStatus_Inlined;
     }
 
     MDefinition* secondArg = callInfo.getArg(1);
 
     MOZ_ASSERT(secondArg->type() == MIRType_Boolean);
-    MOZ_ASSERT(secondArg->isConstantValue());
-
-    bool mustBeRecovered = secondArg->constantValue().toBoolean();
+    MOZ_ASSERT(secondArg->isConstant());
+
+    bool mustBeRecovered = secondArg->toConstant()->value().toBoolean();
     MAssertRecoveredOnBailout* assert =
         MAssertRecoveredOnBailout::New(alloc(), callInfo.getArg(0), mustBeRecovered);
     current->add(assert);
     current->push(assert);
 
     // Create an instruction sequence which implies that the argument of the
     // assertRecoveredOnBailout function would be encoded at least in one
     // Snapshot.
@@ -3490,19 +3490,19 @@ IonBuilder::inlineSimdExtractLane(CallIn
     // for a template object.
     if (callInfo.argc() != 2 || callInfo.constructing()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
     // Lane index.
     MDefinition* arg = callInfo.getArg(1);
-    if (!arg->isConstantValue() || arg->type() != MIRType_Int32)
+    if (!arg->isConstant() || arg->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
-    int32_t lane = arg->constantValue().toInt32();
+    int32_t lane = arg->toConstant()->value().toInt32();
     if (lane < 0 || lane >= 4)
         return InliningStatus_NotInlined;
 
     // Original vector.
     MDefinition* orig = unboxSimd(callInfo.getArg(0), type);
     MIRType vecType = orig->type();
     MIRType laneType = SimdTypeToLaneType(vecType);
     SimdSign sign = GetSimdSign(type);
@@ -3523,20 +3523,20 @@ IonBuilder::InliningStatus
 IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdType type)
 {
     InlineTypedObject* templateObj = nullptr;
     if (!canInlineSimd(callInfo, native, 3, &templateObj))
         return InliningStatus_NotInlined;
 
     // Lane index.
     MDefinition* arg = callInfo.getArg(1);
-    if (!arg->isConstantValue() || arg->type() != MIRType_Int32)
+    if (!arg->isConstant() || arg->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
 
-    int32_t lane = arg->constantValue().toInt32();
+    int32_t lane = arg->toConstant()->value().toInt32();
     if (lane < 0 || lane >= 4)
         return InliningStatus_NotInlined;
 
     // Original vector.
     MDefinition* orig = unboxSimd(callInfo.getArg(0), type);
     MIRType vecType = orig->type();
 
     // Convert to 0 / -1 before inserting a boolean lane.
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -73,57 +73,29 @@ MDefinition::PrintOpcodeName(GenericPrin
 #undef NAME
     };
     const char* name = names[op];
     size_t len = strlen(name);
     for (size_t i = 0; i < len; i++)
         out.printf("%c", tolower(name[i]));
 }
 
-const Value&
-MDefinition::constantValue()
-{
-    MOZ_ASSERT(isConstantValue());
-
-    if (isBox())
-        return getOperand(0)->constantValue();
-    return toConstant()->value();
-}
-
-const Value*
-MDefinition::constantVp()
-{
-    MOZ_ASSERT(isConstantValue());
-    if (isBox())
-        return getOperand(0)->constantVp();
-    return toConstant()->vp();
-}
-
-bool
-MDefinition::constantToBoolean()
-{
-    MOZ_ASSERT(isConstantValue());
-    if (isBox())
-        return getOperand(0)->constantToBoolean();
-    return toConstant()->valueToBoolean();
-}
-
 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()));
 
-    if (!left->isConstantValue() || !right->isConstantValue())
+    if (!left->isConstant() || !right->isConstant())
         return nullptr;
 
-    Value lhs = left->constantValue();
-    Value rhs = right->constantValue();
+    Value lhs = left->toConstant()->value();
+    Value rhs = right->toConstant()->value();
     Value ret = UndefinedValue();
 
     switch (ins->op()) {
       case MDefinition::Op_BitAnd:
         ret = Int32Value(lhs.toInt32() & rhs.toInt32());
         break;
       case MDefinition::Op_BitOr:
         ret = Int32Value(lhs.toInt32() | rhs.toInt32());
@@ -184,20 +156,20 @@ EvaluateExactReciprocal(TempAllocator& a
 {
     // we should fold only when it is a floating point operation
     if (!IsFloatingPointType(ins->type()))
         return nullptr;
 
     MDefinition* left = ins->getOperand(0);
     MDefinition* right = ins->getOperand(1);
 
-    if (!right->isConstantValue())
+    if (!right->isConstant())
         return nullptr;
 
-    Value rhs = right->constantValue();
+    Value rhs = right->toConstant()->value();
 
     int32_t num;
     if (!mozilla::NumberIsInt32(rhs.toNumber(), &num))
         return nullptr;
 
     // check if rhs is a power of two
     if (mozilla::Abs(num) & (mozilla::Abs(num) - 1))
         return nullptr;
@@ -392,18 +364,19 @@ MTest::foldsTo(TempAllocator& alloc)
     if (op->isNot()) {
         // If the operand of the Not is itself a Not, they cancel out.
         MDefinition* opop = op->getOperand(0);
         if (opop->isNot())
             return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse());
         return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue());
     }
 
-    if (op->isConstantValue() && !op->constantValue().isMagic())
-        return MGoto::New(alloc, op->constantToBoolean() ? ifTrue() : ifFalse());
+    MConstant* opConst = op->maybeConstantValue();
+    if (opConst && !opConst->value().isMagic())
+        return MGoto::New(alloc, opConst->valueToBoolean() ? ifTrue() : ifFalse());
 
     switch (op->type()) {
       case MIRType_Undefined:
       case MIRType_Null:
         return MGoto::New(alloc, ifFalse());
       case MIRType_Symbol:
         return MGoto::New(alloc, ifTrue());
       case MIRType_Object:
@@ -908,46 +881,46 @@ MSimdValueX4::foldsTo(TempAllocator& all
 {
     DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type());
     bool allConstants = true;
     bool allSame = true;
 
     for (size_t i = 0; i < 4; ++i) {
         MDefinition* op = getOperand(i);
         MOZ_ASSERT(op->type() == laneType);
-        if (!op->isConstantValue())
+        if (!op->isConstant())
             allConstants = false;
         if (i > 0 && op != getOperand(i - 1))
             allSame = false;
     }
 
     if (!allConstants && !allSame)
         return this;
 
     if (allConstants) {
         SimdConstant cst;
         switch (type()) {
           case MIRType_Bool32x4: {
             int32_t a[4];
             for (size_t i = 0; i < 4; ++i)
-                a[i] = getOperand(i)->constantToBoolean() ? -1 : 0;
+                a[i] = getOperand(i)->toConstant()->valueToBoolean() ? -1 : 0;
             cst = SimdConstant::CreateX4(a);
             break;
           }
           case MIRType_Int32x4: {
             int32_t a[4];
             for (size_t i = 0; i < 4; ++i)
-                a[i] = getOperand(i)->constantValue().toInt32();
+                a[i] = getOperand(i)->toConstant()->value().toInt32();
             cst = SimdConstant::CreateX4(a);
             break;
           }
           case MIRType_Float32x4: {
             float a[4];
             for (size_t i = 0; i < 4; ++i)
-                a[i] = getOperand(i)->constantValue().toNumber();
+                a[i] = getOperand(i)->toConstant()->value().toNumber();
             cst = SimdConstant::CreateX4(a);
             break;
           }
           default: MOZ_CRASH("unexpected type in MSimdValueX4::foldsTo");
         }
 
         return MSimdConstant::New(alloc, cst, type());
     }
@@ -956,34 +929,34 @@ MSimdValueX4::foldsTo(TempAllocator& all
     return MSimdSplatX4::New(alloc, getOperand(0), type());
 }
 
 MDefinition*
 MSimdSplatX4::foldsTo(TempAllocator& alloc)
 {
     DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type());
     MDefinition* op = getOperand(0);
-    if (!op->isConstantValue())
+    if (!op->isConstant())
         return this;
     MOZ_ASSERT(op->type() == laneType);
 
     SimdConstant cst;
     switch (type()) {
       case MIRType_Bool32x4: {
-        int32_t v = op->constantToBoolean() ? -1 : 0;
+        int32_t v = op->toConstant()->valueToBoolean() ? -1 : 0;
         cst = SimdConstant::SplatX4(v);
         break;
       }
       case MIRType_Int32x4: {
-        int32_t v = op->constantValue().toInt32();
+        int32_t v = op->toConstant()->value().toInt32();
         cst = SimdConstant::SplatX4(v);
         break;
       }
       case MIRType_Float32x4: {
-        float v = op->constantValue().toNumber();
+        float v = op->toConstant()->value().toNumber();
         cst = SimdConstant::SplatX4(v);
         break;
       }
       default: MOZ_CRASH("unexpected type in MSimdSplatX4::foldsTo");
     }
 
     return MSimdConstant::New(alloc, cst, type());
 }
@@ -1396,20 +1369,20 @@ MMathFunction::foldsTo(TempAllocator& al
         return MConstant::NewTypedValue(alloc, DoubleValue(out), MIRType_Float32);
     return MConstant::New(alloc, DoubleValue(out));
 }
 
 MDefinition*
 MAtomicIsLockFree::foldsTo(TempAllocator& alloc)
 {
     MDefinition* input = getOperand(0);
-    if (!input->isConstantValue())
+    if (!input->isConstant())
         return this;
 
-    Value val = input->constantValue();
+    Value val = input->toConstant()->value();
     if (!val.isInt32())
         return this;
 
     return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfree(val.toInt32())));
 }
 
 MParameter*
 MParameter::New(TempAllocator& alloc, int32_t index, TemporaryTypeSet* types)
@@ -1588,32 +1561,32 @@ MApplyArray::New(TempAllocator& alloc, J
                  MDefinition* self)
 {
     return new(alloc) MApplyArray(target, fun, elements, self);
 }
 
 MDefinition*
 MStringLength::foldsTo(TempAllocator& alloc)
 {
-    if ((type() == MIRType_Int32) && (string()->isConstantValue())) {
-        Value value = string()->constantValue();
+    if (type() == MIRType_Int32 && string()->isConstant()) {
+        Value value = string()->toConstant()->value();
         JSAtom* atom = &value.toString()->asAtom();
         return MConstant::New(alloc, Int32Value(atom->length()));
     }
 
     return this;
 }
 
 MDefinition*
 MConcat::foldsTo(TempAllocator& alloc)
 {
-    if (lhs()->isConstantValue() && lhs()->constantValue().toString()->empty())
+    if (lhs()->isConstant() && lhs()->toConstant()->value().toString()->empty())
         return rhs();
 
-    if (rhs()->isConstantValue() && rhs()->constantValue().toString()->empty())
+    if (rhs()->isConstant() && rhs()->toConstant()->value().toString()->empty())
         return lhs();
 
     return this;
 }
 
 static bool
 EnsureFloatInputOrConvert(MUnaryInstruction* owner, TempAllocator& alloc)
 {
@@ -2299,22 +2272,24 @@ MBinaryBitwiseInstruction::foldUnnecessa
 
     if (IsConstant(rhs, -1))
         return foldIfNegOne(1);
 
     if (lhs == rhs)
         return foldIfEqual();
 
     if (maskMatchesRightRange) {
-        MOZ_ASSERT(lhs->isConstantValue() && lhs->type() == MIRType_Int32);
+        MOZ_ASSERT(lhs->isConstant());
+        MOZ_ASSERT(lhs->type() == MIRType_Int32);
         return foldIfAllBitsSet(0);
     }
 
     if (maskMatchesLeftRange) {
-        MOZ_ASSERT(rhs->isConstantValue() && rhs->type() == MIRType_Int32);
+        MOZ_ASSERT(rhs->isConstant());
+        MOZ_ASSERT(rhs->type() == MIRType_Int32);
         return foldIfAllBitsSet(1);
     }
 
     return this;
 }
 
 void
 MBinaryBitwiseInstruction::infer(BaselineInspector*, jsbytecode*)
@@ -2365,22 +2340,23 @@ MUrsh::infer(BaselineInspector* inspecto
         return;
     }
 
     specialization_ = MIRType_Int32;
     setResultType(MIRType_Int32);
 }
 
 static inline bool
-CanProduceNegativeZero(MDefinition* def) {
+CanProduceNegativeZero(MDefinition* def)
+{
     // Test if this instruction can produce negative zero even when bailing out
     // and changing types.
     switch (def->op()) {
         case MDefinition::Op_Constant:
-            if (def->type() == MIRType_Double && def->constantValue().toDouble() == -0.0)
+            if (def->type() == MIRType_Double && def->toConstant()->value().toDouble() == -0.0)
                 return true;
             MOZ_FALLTHROUGH;
         case MDefinition::Op_BitAnd:
         case MDefinition::Op_BitOr:
         case MDefinition::Op_BitXor:
         case MDefinition::Op_BitNot:
         case MDefinition::Op_Lsh:
         case MDefinition::Op_Rsh:
@@ -2695,18 +2671,19 @@ MMinMax::foldsTo(TempAllocator& alloc)
             MOZ_ASSERT(IsFloatingPointType(type()));
             MConstant* constant = MConstant::New(alloc, DoubleValue(result));
             if (type() == MIRType_Float32)
                 constant->setResultType(MIRType_Float32);
             return constant;
         }
     }
 
-    MDefinition* operand = lhs()->isConstantValue() ? rhs() : lhs();
-    const js::Value& val = lhs()->isConstantValue() ? lhs()->constantValue() : rhs()->constantValue();
+    MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
+    const js::Value& val =
+        lhs()->isConstant() ? lhs()->toConstant()->value() : rhs()->toConstant()->value();
 
     if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) {
         // min(int32, cte >= INT32_MAX) = int32
         if (val.isDouble() && val.toDouble() >= INT32_MAX && !isMax()) {
             MLimitedTruncate* limit =
                 MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
             block()->insertBefore(this, limit);
             MToDouble* toDouble = MToDouble::New(alloc, limit);
@@ -2765,36 +2742,39 @@ MDiv::foldsTo(TempAllocator& alloc)
 
 void
 MDiv::analyzeEdgeCasesForward()
 {
     // This is only meaningful when doing integer division.
     if (specialization_ != MIRType_Int32)
         return;
 
+    MOZ_ASSERT(lhs()->type() == MIRType_Int32);
+    MOZ_ASSERT(rhs()->type() == MIRType_Int32);
+
     // Try removing divide by zero check
-    if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0))
+    if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0))
         canBeDivideByZero_ = false;
 
     // If lhs is a constant int != INT32_MIN, then
     // negative overflow check can be skipped.
-    if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(INT32_MIN))
+    if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(INT32_MIN))
         canBeNegativeOverflow_ = false;
 
     // If rhs is a constant int != -1, likewise.
-    if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(-1))
+    if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(-1))
         canBeNegativeOverflow_ = false;
 
     // If lhs is != 0, then negative zero check can be skipped.
-    if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(0))
+    if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(0))
         setCanBeNegativeZero(false);
 
     // If rhs is >= 0, likewise.
-    if (rhs()->isConstantValue()) {
-        const js::Value& val = rhs()->constantValue();
+    if (rhs()->isConstant()) {
+        const js::Value& val = rhs()->toConstant()->value();
         if (val.isInt32() && val.toInt32() >= 0)
             setCanBeNegativeZero(false);
     }
 }
 
 void
 MDiv::analyzeEdgeCasesBackward()
 {
@@ -2822,21 +2802,21 @@ MMod::foldsTo(TempAllocator& alloc)
 
 void
 MMod::analyzeEdgeCasesForward()
 {
     // These optimizations make sense only for integer division
     if (specialization_ != MIRType_Int32)
         return;
 
-    if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0))
+    if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0))
         canBeDivideByZero_ = false;
 
-    if (rhs()->isConstantValue()) {
-        int32_t n = rhs()->constantValue().toInt32();
+    if (rhs()->isConstant()) {
+        int32_t n = rhs()->toConstant()->value().toInt32();
         if (n > 0 && !IsPowerOfTwo(n))
             canBePowerOfTwoDivisor_ = false;
     }
 }
 
 bool
 MMod::fallible() const
 {
@@ -2912,25 +2892,25 @@ void
 MMul::analyzeEdgeCasesForward()
 {
     // Try to remove the check for negative zero
     // This only makes sense when using the integer multiplication
     if (specialization() != MIRType_Int32)
         return;
 
     // If lhs is > 0, no need for negative zero check.
-    if (lhs()->isConstantValue()) {
-        const js::Value& val = lhs()->constantValue();
+    if (lhs()->isConstant()) {
+        const js::Value& val = lhs()->toConstant()->value();
         if (val.isInt32() && val.toInt32() > 0)
             setCanBeNegativeZero(false);
     }
 
     // If rhs is > 0, likewise.
-    if (rhs()->isConstantValue()) {
-        const js::Value& val = rhs()->constantValue();
+    if (rhs()->isConstant()) {
+        const js::Value& val = rhs()->toConstant()->value();
         if (val.isInt32() && val.toInt32() > 0)
             setCanBeNegativeZero(false);
     }
 }
 
 void
 MMul::analyzeEdgeCasesBackward()
 {
@@ -3019,30 +2999,26 @@ MCompare::inputType()
         MOZ_CRASH("No known conversion");
     }
 }
 
 static inline bool
 MustBeUInt32(MDefinition* def, MDefinition** pwrapped)
 {
     if (def->isUrsh()) {
-        *pwrapped = def->toUrsh()->getOperand(0);
-        MDefinition* rhs = def->toUrsh()->getOperand(1);
-        return !def->toUrsh()->bailoutsDisabled()
-            && rhs->isConstantValue()
-            && rhs->constantValue().isInt32()
-            && rhs->constantValue().toInt32() == 0;
+        *pwrapped = def->toUrsh()->lhs();
+        MDefinition* rhs = def->toUrsh()->rhs();
+        return !def->toUrsh()->bailoutsDisabled() &&
+               rhs->maybeConstantValue() &&
+               rhs->maybeConstantValue()->value().isInt32(0);
     }
 
-    if (def->isConstantValue()) {
-        if (def->isBox())
-            def = def->toBox()->getOperand(0);
-        *pwrapped = def;
-        return def->constantValue().isInt32()
-            && def->constantValue().toInt32() >= 0;
+    if (MConstant* defConst = def->maybeConstantValue()) {
+        *pwrapped = defConst;
+        return defConst->value().isInt32(0);
     }
 
     return false;
 }
 
 /* static */ bool
 MBinaryInstruction::unsignedOperands(MDefinition* left, MDefinition* right)
 {
@@ -3181,17 +3157,17 @@ MDefinition*
 MBitNot::foldsTo(TempAllocator& alloc)
 {
     if (specialization_ != MIRType_Int32)
         return this;
 
     MDefinition* input = getOperand(0);
 
     if (input->isConstant()) {
-        js::Value v = Int32Value(~(input->constantValue().toInt32()));
+        js::Value v = Int32Value(~(input->toConstant()->value().toInt32()));
         return MConstant::New(alloc, v);
     }
 
     if (input->isBitNot() && input->toBitNot()->specialization_ == MIRType_Int32) {
         MOZ_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType_Int32);
         return MTruncateToInt32::New(alloc, input->toBitNot()->input()); // ~~x => x | 0
     }
 
@@ -3547,17 +3523,17 @@ MTruncateToInt32::foldsTo(TempAllocator&
     MDefinition* input = getOperand(0);
     if (input->isBox())
         input = input->getOperand(0);
 
     if (input->type() == MIRType_Int32)
         return input;
 
     if (input->type() == MIRType_Double && input->isConstant()) {
-        const Value& v = input->constantValue();
+        const Value& v = input->toConstant()->value();
         int32_t ret = ToInt32(v.toDouble());
         return MConstant::New(alloc, Int32Value(ret));
     }
 
     return this;
 }
 
 MDefinition*
@@ -3617,18 +3593,18 @@ MToString::foldsTo(TempAllocator& alloc)
     if (in->type() == MIRType_String)
         return in;
     return this;
 }
 
 MDefinition*
 MClampToUint8::foldsTo(TempAllocator& alloc)
 {
-    if (input()->isConstantValue()) {
-        const Value& v = input()->constantValue();
+    if (MConstant* inputConst = input()->maybeConstantValue()) {
+        const Value& v = inputConst->value();
         if (v.isDouble()) {
             int32_t clamped = ClampDoubleToUint8(v.toDouble());
             return MConstant::New(alloc, Int32Value(clamped));
         }
         if (v.isInt32()) {
             int32_t clamped = ClampIntForUint8Array(v.toInt32());
             return MConstant::New(alloc, Int32Value(clamped));
         }
@@ -3675,21 +3651,21 @@ MCompare::tryFoldEqualOperands(bool* res
     return true;
 }
 
 bool
 MCompare::tryFoldTypeOf(bool* result)
 {
     if (!lhs()->isTypeOf() && !rhs()->isTypeOf())
         return false;
-    if (!lhs()->isConstantValue() && !rhs()->isConstantValue())
+    if (!lhs()->isConstant() && !rhs()->isConstant())
         return false;
 
     MTypeOf* typeOf = lhs()->isTypeOf() ? lhs()->toTypeOf() : rhs()->toTypeOf();
-    const Value* constant = lhs()->isConstantValue() ? lhs()->constantVp() : rhs()->constantVp();
+    const Value* constant = lhs()->isConstant() ? lhs()->toConstant()->vp() : rhs()->toConstant()->vp();
 
     if (!constant->isString())
         return false;
 
     if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE &&
         jsop() != JSOP_EQ && jsop() != JSOP_NE)
     {
         return false;
@@ -4073,18 +4049,18 @@ MNot::cacheOperandMightEmulateUndefined(
     if (!getOperand(0)->maybeEmulatesUndefined(constraints))
         markNoOperandEmulatesUndefined();
 }
 
 MDefinition*
 MNot::foldsTo(TempAllocator& alloc)
 {
     // Fold if the input is constant
-    if (input()->isConstantValue() && !input()->constantValue().isMagic()) {
-        bool result = input()->constantToBoolean();
+    if (input()->maybeConstantValue() && !input()->maybeConstantValue()->value().isMagic()) {
+        bool result = input()->maybeConstantValue()->valueToBoolean();
         if (type() == MIRType_Int32)
             return MConstant::New(alloc, Int32Value(!result));
 
         // ToBoolean can't cause side effects, so this is safe.
         return MConstant::New(alloc, BooleanValue(!result));
     }
 
     // If the operand of the Not is itself a Not, they cancel out. But we can't
@@ -4924,30 +4900,30 @@ MGetPropertyCache::updateForReplacement(
     MGetPropertyCache* other = ins->toGetPropertyCache();
     location_.append(&other->location_);
     return true;
 }
 
 MDefinition*
 MAsmJSUnsignedToDouble::foldsTo(TempAllocator& alloc)
 {
-    if (input()->isConstantValue()) {
-        const Value& v = input()->constantValue();
+    if (input()->isConstant()) {
+        const Value& v = input()->toConstant()->value();
         if (v.isInt32())
             return MConstant::New(alloc, DoubleValue(uint32_t(v.toInt32())));
     }
 
     return this;
 }
 
 MDefinition*
 MAsmJSUnsignedToFloat32::foldsTo(TempAllocator& alloc)
 {
-    if (input()->isConstantValue()) {
-        const Value& v = input()->constantValue();
+    if (input()->isConstant()) {
+        const Value& v = input()->toConstant()->value();
         if (v.isInt32()) {
             double dval = double(uint32_t(v.toInt32()));
             if (IsFloat32Representable(dval))
                 return MConstant::NewAsmJS(alloc, JS::Float32Value(float(dval)), MIRType_Float32);
         }
     }
 
     return this;
@@ -4986,52 +4962,52 @@ MSqrt::trySpecializeFloat32(TempAllocato
 
     setResultType(MIRType_Float32);
     specialization_ = MIRType_Float32;
 }
 
 MDefinition*
 MClz::foldsTo(TempAllocator& alloc)
 {
-    if (num()->isConstantValue()) {
-        int32_t n = num()->constantValue().toInt32();
+    if (num()->isConstant()) {
+        int32_t n = num()->toConstant()->value().toInt32();
         if (n == 0)
             return MConstant::New(alloc, Int32Value(32));
         return MConstant::New(alloc, Int32Value(mozilla::CountLeadingZeroes32(n)));
     }
 
     return this;
 }
 
 MDefinition*
 MBoundsCheck::foldsTo(TempAllocator& alloc)
 {
-    if (index()->isConstantValue() && length()->isConstantValue()) {
-       uint32_t len = length()->constantValue().toInt32();
-       uint32_t idx = index()->constantValue().toInt32();
-       if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len)
-           return index();
+    if (index()->isConstant() && length()->isConstant()) {
+        uint32_t len = length()->toConstant()->value().toInt32();
+        uint32_t idx = index()->toConstant()->value().toInt32();
+        if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len)
+            return index();
     }
 
     return this;
 }
 
 MDefinition*
 MTableSwitch::foldsTo(TempAllocator& alloc)
 {
     MDefinition* op = getOperand(0);
 
     // If we only have one successor, convert to a plain goto to the only
     // successor. TableSwitch indices are numeric; other types will always go to
     // the only successor.
     if (numSuccessors() == 1 || (op->type() != MIRType_Value && !IsNumberType(op->type())))
         return MGoto::New(alloc, getDefault());
 
-    if (op->isConstantValue()) {
-        Value v = op->constantValue();
+    if (MConstant* opConst = op->maybeConstantValue()) {
+        Value v = opConst->value();
         if (v.isInt32()) {
             int32_t i = v.toInt32() - low_;
             MBasicBlock* target;
             if (size_t(i) < numCases())
                 target = getCase(size_t(i));
             else
                 target = getDefault();
             MOZ_ASSERT(target);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -846,22 +846,17 @@ class MDefinition : public MNode
         return this->to<M##opcode>();     \
     }                                     \
     const M##opcode* to##opcode() const { \
         return this->to<M##opcode>();     \
     }
     MIR_OPCODE_LIST(OPCODE_CASTS)
 #   undef OPCODE_CASTS
 
-    bool isConstantValue() const {
-        return isConstant() || (isBox() && getOperand(0)->isConstant());
-    }
-    const Value& constantValue();
-    const Value* constantVp();
-    bool constantToBoolean();
+    inline MConstant* maybeConstantValue();
 
     inline MInstruction* toInstruction();
     inline const MInstruction* toInstruction() const;
     bool isInstruction() const {
         return !isPhi();
     }
 
     virtual bool isControlInstruction() const {
@@ -14262,45 +14257,62 @@ void MUse::releaseProducer()
 {
     MOZ_ASSERT(consumer_, "Clearing MUse without a consumer");
     producer_->removeUse(this);
     producer_ = nullptr;
 }
 
 // Implement cast functions now that the compiler can see the inheritance.
 
-MDefinition* MNode::toDefinition()
+MDefinition*
+MNode::toDefinition()
 {
     MOZ_ASSERT(isDefinition());
     return (MDefinition*)this;
 }
 
-MResumePoint* MNode::toResumePoint()
+MResumePoint*
+MNode::toResumePoint()
 {
     MOZ_ASSERT(isResumePoint());
     return (MResumePoint*)this;
 }
 
-MInstruction* MDefinition::toInstruction()
+MInstruction*
+MDefinition::toInstruction()
 {
     MOZ_ASSERT(!isPhi());
     return (MInstruction*)this;
 }
 
-const MInstruction* MDefinition::toInstruction() const
+const MInstruction*
+MDefinition::toInstruction() const
 {
     MOZ_ASSERT(!isPhi());
     return (const MInstruction*)this;
 }
 
-MControlInstruction* MDefinition::toControlInstruction() {
+MControlInstruction*
+MDefinition::toControlInstruction()
+{
     MOZ_ASSERT(isControlInstruction());
     return (MControlInstruction*)this;
 }
 
+MConstant*
+MDefinition::maybeConstantValue()
+{
+    MDefinition* op = this;
+    if (op->isBox())
+        op = op->toBox()->input();
+    if (op->isConstant())
+        return op->toConstant();
+    return nullptr;
+}
+
 // Helper functions used to decide how to build MIR.
 
 bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
                                 MDefinition* obj, MDefinition* id);
 JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
                                     MDefinition* id);
 bool ElementAccessIsTypedArray(CompilerConstraintList* constraints,
                                MDefinition* obj, MDefinition* id,
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -191,22 +191,24 @@ RangeAnalysis::addBetaNodes()
         JSOp jsop = compare->jsop();
 
         if (branch_dir == FALSE_BRANCH) {
             jsop = NegateCompareOp(jsop);
             conservativeLower = GenericNaN();
             conservativeUpper = GenericNaN();
         }
 
-        if (left->isConstantValue() && left->constantValue().isNumber()) {
-            bound = left->constantValue().toNumber();
+        MConstant* leftConst = left->maybeConstantValue();
+        MConstant* rightConst = right->maybeConstantValue();
+        if (leftConst && leftConst->value().isNumber()) {
+            bound = leftConst->value().toNumber();
             val = right;
             jsop = ReverseCompareOp(jsop);
-        } else if (right->isConstantValue() && right->constantValue().isNumber()) {
-            bound = right->constantValue().toNumber();
+        } else if (rightConst && rightConst->value().isNumber()) {
+            bound = rightConst->value().toNumber();
             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) {
@@ -1355,37 +1357,37 @@ MBitNot::computeRange(TempAllocator& all
 
 void
 MLsh::computeRange(TempAllocator& alloc)
 {
     Range left(getOperand(0));
     Range right(getOperand(1));
     left.wrapAroundToInt32();
 
-    MDefinition* rhs = getOperand(1);
-    if (rhs->isConstantValue() && rhs->constantValue().isInt32()) {
-        int32_t c = rhs->constantValue().toInt32();
+    MConstant* rhsConst = getOperand(1)->maybeConstantValue();
+    if (rhsConst && rhsConst->type() == MIRType_Int32) {
+        int32_t c = rhsConst->value().toInt32();
         setRange(Range::lsh(alloc, &left, c));
         return;
     }
 
     right.wrapAroundToShiftCount();
     setRange(Range::lsh(alloc, &left, &right));
 }
 
 void
 MRsh::computeRange(TempAllocator& alloc)
 {
     Range left(getOperand(0));
     Range right(getOperand(1));
     left.wrapAroundToInt32();
 
-    MDefinition* rhs = getOperand(1);
-    if (rhs->isConstantValue() && rhs->constantValue().isInt32()) {
-        int32_t c = rhs->constantValue().toInt32();
+    MConstant* rhsConst = getOperand(1)->maybeConstantValue();
+    if (rhsConst && rhsConst->type() == MIRType_Int32) {
+        int32_t c = rhsConst->value().toInt32();
         setRange(Range::rsh(alloc, &left, c));
         return;
     }
 
     right.wrapAroundToShiftCount();
     setRange(Range::rsh(alloc, &left, &right));
 }
 
@@ -1398,19 +1400,19 @@ MUrsh::computeRange(TempAllocator& alloc
     // ursh can be thought of as converting its left operand to uint32, or it
     // can be thought of as converting its left operand to int32, and then
     // reinterpreting the int32 bits as a uint32 value. Both approaches yield
     // the same result. Since we lack support for full uint32 ranges, we use
     // the second interpretation, though it does cause us to be conservative.
     left.wrapAroundToInt32();
     right.wrapAroundToShiftCount();
 
-    MDefinition* rhs = getOperand(1);
-    if (rhs->isConstantValue() && rhs->constantValue().isInt32()) {
-        int32_t c = rhs->constantValue().toInt32();
+    MConstant* rhsConst = getOperand(1)->maybeConstantValue();
+    if (rhsConst && rhsConst->type() == MIRType_Int32) {
+        int32_t c = rhsConst->value().toInt32();
         setRange(Range::ursh(alloc, &left, c));
     } else {
         setRange(Range::ursh(alloc, &left, &right));
     }
 
     MOZ_ASSERT(range()->lower() >= 0);
 }
 
@@ -2800,17 +2802,17 @@ CloneForDeadBranches(TempAllocator& allo
     clone->setRange(nullptr);
 
     // Set UseRemoved flag on the cloned instruction in order to chain recover
     // instruction for the bailout path.
     clone->setUseRemovedUnchecked();
 
     candidate->block()->insertBefore(candidate, clone);
 
-    if (!candidate->isConstantValue()) {
+    if (!candidate->maybeConstantValue()) {
         MOZ_ASSERT(clone->canRecoverOnBailout());
         clone->setRecoveredOnBailout();
     }
 
     // Replace the candidate by its recovered on bailout clone within recovered
     // instructions and resume points operands.
     for (MUseIterator i(candidate->usesBegin()); i != candidate->usesEnd(); ) {
         MUse* use = *i++;
@@ -3350,24 +3352,24 @@ DoesMaskMatchRange(int32_t mask, Range& 
 }
 
 void
 MBinaryBitwiseInstruction::collectRangeInfoPreTrunc()
 {
     Range lhsRange(lhs());
     Range rhsRange(rhs());
 
-    if (lhs()->isConstantValue() && lhs()->type() == MIRType_Int32 &&
-         DoesMaskMatchRange(lhs()->constantValue().toInt32(), rhsRange))
+    if (lhs()->isConstant() && lhs()->type() == MIRType_Int32 &&
+        DoesMaskMatchRange(lhs()->toConstant()->value().toInt32(), rhsRange))
     {
         maskMatchesRightRange = true;
     }
 
-    if (rhs()->isConstantValue() && rhs()->type() == MIRType_Int32 &&
-         DoesMaskMatchRange(rhs()->constantValue().toInt32(), lhsRange))
+    if (rhs()->isConstant() && rhs()->type() == MIRType_Int32 &&
+        DoesMaskMatchRange(rhs()->toConstant()->value().toInt32(), lhsRange))
     {
         maskMatchesLeftRange = true;
     }
 }
 
 bool
 RangeAnalysis::prepareForUCE(bool* shouldRemoveDeadCode)
 {
--- a/js/src/jit/ScalarReplacement.cpp
+++ b/js/src/jit/ScalarReplacement.cpp
@@ -775,20 +775,21 @@ static bool
 IndexOf(MDefinition* ins, int32_t* res)
 {
     MOZ_ASSERT(ins->isLoadElement() || ins->isStoreElement());
     MDefinition* indexDef = ins->getOperand(1); // ins->index();
     if (indexDef->isBoundsCheck())
         indexDef = indexDef->toBoundsCheck()->index();
     if (indexDef->isToInt32())
         indexDef = indexDef->toToInt32()->getOperand(0);
-    if (!indexDef->isConstantValue())
+    MConstant* indexDefConst = indexDef->maybeConstantValue();
+    if (!indexDefConst)
         return false;
 
-    Value index = indexDef->constantValue();
+    Value index = indexDefConst->value();
     if (!index.isInt32())
         return false;
     *res = index.toInt32();
     return true;
 }
 
 // Returns False if the elements is not escaped and if it is optimizable by
 // ScalarReplacementOfArray.
@@ -1253,17 +1254,17 @@ ArrayMemoryView::visitSetInitializedLeng
     // To obtain the length, we need to add 1 to it, and thus we need to create
     // a new constant that we register in the ArrayState.
     state_ = BlockState::Copy(alloc_, state_);
     if (!state_) {
         oom_ = true;
         return;
     }
 
-    int32_t initLengthValue = ins->index()->constantValue().toInt32() + 1;
+    int32_t initLengthValue = ins->index()->maybeConstantValue()->value().toInt32() + 1;
     MConstant* initLength = MConstant::New(alloc_, Int32Value(initLengthValue));
     ins->block()->insertBefore(ins, initLength);
     ins->block()->insertBefore(ins, state_);
     state_->setInitializedLength(initLength);
 
     // Remove original instruction.
     discardInstruction(ins, elements);
 }
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -461,37 +461,37 @@ LIRGeneratorARM::visitAsmJSUnsignedToFlo
 void
 LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
 {
     MDefinition* ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
     // For the ARM it is best to keep the 'ptr' in a register if a bounds check is needed.
-    if (ptr->isConstantValue() && !ins->needsBoundsCheck()) {
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
         // A bounds check is only skipped for a positive index.
-        MOZ_ASSERT(ptr->constantValue().toInt32() >= 0);
-        ptrAlloc = LAllocation(ptr->constantVp());
+        MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0);
+        ptrAlloc = LAllocation(ptr->toConstant()->vp());
     } else {
         ptrAlloc = useRegisterAtStart(ptr);
     }
 
     define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
 }
 
 void
 LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
 {
     MDefinition* ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
-    if (ptr->isConstantValue() && !ins->needsBoundsCheck()) {
-        MOZ_ASSERT(ptr->constantValue().toInt32() >= 0);
-        ptrAlloc = LAllocation(ptr->constantVp());
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
+        MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0);
+        ptrAlloc = LAllocation(ptr->toConstant()->vp());
     } else {
         ptrAlloc = useRegisterAtStart(ptr);
     }
 
     add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
 }
 
 void