Bug 1010586 - IonMonkey: Shrink the MUse class by making the index field unnecessary. r=nbp
authorDan Gohman <sunfish@mozilla.com>
Tue, 20 May 2014 18:43:15 -0700
changeset 184045 0e9ed96596b14b99a692d1b8415fb68b11d42abc
parent 184044 179363be564197fc8907d08823bd06609257ece4
child 184046 d016c59f0876a3a99913bf057a8c3047cfbbac5b
push id26810
push usercbook@mozilla.com
push dateWed, 21 May 2014 11:46:36 +0000
treeherdermozilla-central@50fb8c4db2fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1010586
milestone32.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 1010586 - IonMonkey: Shrink the MUse class by making the index field unnecessary. r=nbp
js/src/jit/EffectiveAddressAnalysis.cpp
js/src/jit/IonAnalysis.cpp
js/src/jit/Lowering.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/RangeAnalysis.cpp
--- a/js/src/jit/EffectiveAddressAnalysis.cpp
+++ b/js/src/jit/EffectiveAddressAnalysis.cpp
@@ -40,17 +40,17 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *l
         MUseIterator use = last->usesBegin();
         if (!use->consumer()->isDefinition() || !use->consumer()->toDefinition()->isAdd())
             break;
 
         MAdd *add = use->consumer()->toDefinition()->toAdd();
         if (add->specialization() != MIRType_Int32 || !add->isTruncated())
             break;
 
-        MDefinition *other = add->getOperand(1 - use->index());
+        MDefinition *other = add->getOperand(1 - add->indexOf(*use));
 
         if (other->isConstant()) {
             displacement += other->toConstant()->value().toInt32();
         } else {
             if (base)
                 break;
             base = other;
         }
@@ -66,17 +66,17 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *l
         if (!last->hasOneUse())
             return;
 
         MUseIterator use = last->usesBegin();
         if (!use->consumer()->isDefinition() || !use->consumer()->toDefinition()->isBitAnd())
             return;
 
         MBitAnd *bitAnd = use->consumer()->toDefinition()->toBitAnd();
-        MDefinition *other = bitAnd->getOperand(1 - use->index());
+        MDefinition *other = bitAnd->getOperand(1 - bitAnd->indexOf(*use));
         if (!other->isConstant() || !other->toConstant()->value().isInt32())
             return;
 
         uint32_t bitsClearedByShift = elemSize - 1;
         uint32_t bitsClearedByMask = ~uint32_t(other->toConstant()->value().toInt32());
         if ((bitsClearedByShift & bitsClearedByMask) != bitsClearedByMask)
             return;
 
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2554,17 +2554,17 @@ jit::AnalyzeArgumentsUsage(JSContext *cx
 
     for (MUseDefIterator uses(argumentsValue); uses; uses++) {
         MDefinition *use = uses.def();
 
         // Don't track |arguments| through assignments to phis.
         if (!use->isInstruction())
             return true;
 
-        if (!ArgumentsUseCanBeLazy(cx, script, use->toInstruction(), uses.index(),
+        if (!ArgumentsUseCanBeLazy(cx, script, use->toInstruction(), use->indexOf(uses.use()),
                                    &argumentsContentsObserved))
         {
             return true;
         }
     }
 
     // If a script explicitly accesses the contents of 'arguments', and has
     // formals which may be stored as part of a call object, don't use lazy
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1946,25 +1946,29 @@ MustCloneRegExp(MRegExp *regexp)
     // it escape, we don't have to clone it.
 
     for (MUseIterator iter(regexp->usesBegin()); iter != regexp->usesEnd(); iter++) {
         MNode *node = iter->consumer();
         if (!node->isDefinition())
             return true;
 
         MDefinition *def = node->toDefinition();
-        if (def->isRegExpTest() && iter->index() == 1) {
-            // Optimized RegExp.prototype.test.
-            JS_ASSERT(def->toRegExpTest()->regexp() == regexp);
-            continue;
+        if (def->isRegExpTest()) {
+            MRegExpTest *test = def->toRegExpTest();
+            if (test->indexOf(*iter) == 1) {
+                // Optimized RegExp.prototype.test.
+                JS_ASSERT(test->regexp() == regexp);
+                continue;
+            }
+        } else if (def->isCall()) {
+            MCall *call = def->toCall();
+            if (!MustCloneRegExpForCall(call, call->indexOf(*iter)))
+                continue;
         }
 
-        if (def->isCall() && !MustCloneRegExpForCall(def->toCall(), iter->index()))
-            continue;
-
         return true;
     }
     return false;
 }
 
 bool
 LIRGenerator::visitRegExp(MRegExp *ins)
 {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -25,16 +25,21 @@
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::NumbersAreIdentical;
 using mozilla::IsFloat32Representable;
 using mozilla::Maybe;
 
+size_t MUse::index() const
+{
+    return consumer()->indexOf(this);
+}
+
 template<size_t Op> static void
 ConvertDefinitionToDouble(TempAllocator &alloc, MDefinition *def, MInstruction *consumer)
 {
     MInstruction *replace = MToDouble::New(alloc, def);
     consumer->replaceOperand(Op, replace);
     consumer->block()->insertBefore(consumer, replace);
 }
 
@@ -388,17 +393,16 @@ MDefinition::removeUse(MUseIterator use)
 
 MUseIterator
 MNode::replaceOperand(MUseIterator use, MDefinition *def)
 {
     JS_ASSERT(def != nullptr);
     uint32_t index = use->index();
     MDefinition *prev = use->producer();
 
-    JS_ASSERT(use->index() < numOperands());
     JS_ASSERT(use->producer() == getOperand(index));
     JS_ASSERT(use->consumer() == this);
 
     if (prev == def)
         return use;
 
     MUseIterator result(prev->removeUse(use));
     setOperand(index, def);
@@ -408,17 +412,16 @@ MNode::replaceOperand(MUseIterator use, 
 void
 MNode::replaceOperand(size_t index, MDefinition *def)
 {
     JS_ASSERT(def != nullptr);
     MUse *use = getUseFor(index);
     MDefinition *prev = use->producer();
 
     JS_ASSERT(use->index() == index);
-    JS_ASSERT(use->index() < numOperands());
     JS_ASSERT(use->producer() == getOperand(index));
     JS_ASSERT(use->consumer() == this);
 
     if (prev == def)
         return;
 
     prev->removeUse(use);
     setOperand(index, def);
@@ -432,17 +435,17 @@ MNode::discardOperand(size_t index)
     JS_ASSERT(use->index() == index);
     JS_ASSERT(use->producer() == getOperand(index));
     JS_ASSERT(use->consumer() == this);
 
     use->producer()->removeUse(use);
 
 #ifdef DEBUG
     // Causes any producer/consumer lookups to trip asserts.
-    use->set(nullptr, nullptr, index);
+    use->set(nullptr, nullptr);
 #endif
 }
 
 void
 MDefinition::replaceAllUsesWith(MDefinition *dom)
 {
     JS_ASSERT(dom != nullptr);
     if (dom == this)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -110,51 +110,50 @@ class MControlInstruction;
 
 // Represents a use of a node.
 class MUse : public TempObject, public InlineListNode<MUse>
 {
     friend class MDefinition;
 
     MDefinition *producer_; // MDefinition that is being used.
     MNode *consumer_;       // The node that is using this operand.
-    uint32_t index_;        // The index of this operand in its consumer.
-
-    MUse(MDefinition *producer, MNode *consumer, uint32_t index)
+
+    MUse(MDefinition *producer, MNode *consumer)
       : producer_(producer),
-        consumer_(consumer),
-        index_(index)
+        consumer_(consumer)
     { }
 
   public:
     // Default constructor for use in vectors.
     MUse()
-      : producer_(nullptr), consumer_(nullptr), index_(0)
+      : producer_(nullptr), consumer_(nullptr)
     { }
 
     // Set data inside the MUse.
-    void set(MDefinition *producer, MNode *consumer, uint32_t index) {
+    void set(MDefinition *producer, MNode *consumer) {
         producer_ = producer;
         consumer_ = consumer;
-        index_ = index;
     }
 
     MDefinition *producer() const {
         JS_ASSERT(producer_ != nullptr);
         return producer_;
     }
     bool hasProducer() const {
         return producer_ != nullptr;
     }
     MNode *consumer() const {
         JS_ASSERT(consumer_ != nullptr);
         return consumer_;
     }
-    uint32_t index() const {
-        return index_;
-    }
+
+    // Return the operand index of this MUse in its consumer. In general,
+    // code should prefer to call indexOf on the casted consumer directly,
+    // to allow it to be devirtualized and inlined.
+    size_t index() const;
 };
 
 typedef InlineList<MUse>::iterator MUseIterator;
 
 // A node is an entry in the MIR graph. It has two kinds:
 //   MInstruction: an instruction which appears in the IR stream.
 //   MResumePoint: a list of instructions that correspond to the state of the
 //                 interpreter/Baseline stack.
@@ -182,16 +181,17 @@ class MNode : public TempObject
       : block_(block)
     { }
 
     virtual Kind kind() const = 0;
 
     // Returns the definition at a given operand.
     virtual MDefinition *getOperand(size_t index) const = 0;
     virtual size_t numOperands() const = 0;
+    virtual size_t indexOf(const MUse *u) const = 0;
 
     bool isDefinition() const {
         return kind() == Definition;
     }
     bool isResumePoint() const {
         return kind() == ResumePoint;
     }
     MBasicBlock *block() const {
@@ -223,16 +223,17 @@ class MNode : public TempObject
     virtual void dump() const = 0;
 
   protected:
     // Sets an unset operand, updating use information.
     virtual void setOperand(size_t index, MDefinition *operand) = 0;
 
     // Gets the MUse corresponding to given operand.
     virtual MUse *getUseFor(size_t index) = 0;
+    virtual const MUse *getUseFor(size_t index) const = 0;
 };
 
 class AliasSet {
   private:
     uint32_t flags_;
 
   public:
     enum Flag {
@@ -734,19 +735,16 @@ class MUseDefIterator
         return old;
     }
     MUse *use() const {
         return *current_;
     }
     MDefinition *def() const {
         return current_->consumer()->toDefinition();
     }
-    size_t index() const {
-        return current_->index();
-    }
 };
 
 // An instruction is an SSA name that is inserted into a basic block's IR
 // stream.
 class MInstruction
   : public MDefinition,
     public InlineListNode<MInstruction>
 {
@@ -781,31 +779,40 @@ class MInstruction
 
 template <size_t Arity>
 class MAryInstruction : public MInstruction
 {
   protected:
     mozilla::Array<MUse, Arity> operands_;
 
     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
-        operands_[index].set(operand, this, index);
+        operands_[index].set(operand, this);
         operand->addUse(&operands_[index]);
     }
 
     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
         return &operands_[index];
     }
 
+    const MUse *getUseFor(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
+        return &operands_[index];
+    }
+
   public:
     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
         return operands_[index].producer();
     }
     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
         return Arity;
     }
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        MOZ_ASSERT(u >= &operands_[0]);
+        MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
+        return u - &operands_[0];
+    }
 };
 
 class MNullaryInstruction : public MAryInstruction<0>
 { };
 
 class MUnaryInstruction : public MAryInstruction<1>
 {
   protected:
@@ -1169,25 +1176,30 @@ class MTableSwitch MOZ_FINAL
         high_(high)
     {
         setOperand(0, ins);
     }
 
   protected:
     void setOperand(size_t index, MDefinition *operand) {
         JS_ASSERT(index == 0);
-        operand_.set(operand, this, index);
+        operand_.set(operand, this);
         operand->addUse(&operand_);
     }
 
     MUse *getUseFor(size_t index) {
         JS_ASSERT(index == 0);
         return &operand_;
     }
 
+    const MUse *getUseFor(size_t index) const {
+        JS_ASSERT(index == 0);
+        return &operand_;
+    }
+
   public:
     INSTRUCTION_HEADER(TableSwitch)
     static MTableSwitch *New(TempAllocator &alloc, MDefinition *ins, int32_t low, int32_t high);
 
     size_t numSuccessors() const {
         return successors_.length();
     }
 
@@ -1259,47 +1271,61 @@ class MTableSwitch MOZ_FINAL
         JS_ASSERT(index == 0);
         return operand_.producer();
     }
 
     size_t numOperands() const {
         return 1;
     }
 
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        MOZ_ASSERT(u == getUseFor(0));
+        return 0;
+    }
+
     TypePolicy *typePolicy() {
         return this;
     }
 };
 
 template <size_t Arity, size_t Successors>
 class MAryControlInstruction : public MControlInstruction
 {
     mozilla::Array<MUse, Arity> operands_;
     mozilla::Array<MBasicBlock *, Successors> successors_;
 
   protected:
     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
-        operands_[index].set(operand, this, index);
+        operands_[index].set(operand, this);
         operand->addUse(&operands_[index]);
     }
     void setSuccessor(size_t index, MBasicBlock *successor) {
         successors_[index] = successor;
     }
 
     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
         return &operands_[index];
     }
 
+    const MUse *getUseFor(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
+        return &operands_[index];
+    }
+
   public:
     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
         return operands_[index].producer();
     }
     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
         return Arity;
     }
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        MOZ_ASSERT(u >= &operands_[0]);
+        MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
+        return u - &operands_[0];
+    }
     size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE {
         return Successors;
     }
     MBasicBlock *getSuccessor(size_t i) const MOZ_FINAL MOZ_OVERRIDE {
         return successors_[i];
     }
     void replaceSuccessor(size_t i, MBasicBlock *succ) MOZ_FINAL MOZ_OVERRIDE {
         successors_[i] = succ;
@@ -1901,24 +1927,33 @@ class MVariadicInstruction : public MIns
   public:
     // Will assert if called before initialization.
     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
         return operands_[index].producer();
     }
     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
         return operands_.length();
     }
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        MOZ_ASSERT(u >= &operands_[0]);
+        MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
+        return u - &operands_[0];
+    }
     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
-        operands_[index].set(operand, this, index);
+        operands_[index].set(operand, this);
         operand->addUse(&operands_[index]);
     }
 
     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
         return &operands_[index];
     }
+
+    const MUse *getUseFor(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
+        return &operands_[index];
+    }
 };
 
 class MCall
   : public MVariadicInstruction,
     public CallPolicy
 {
   private:
     // An MCall uses the MPrepareCall, MDefinition for the function, and
@@ -4708,16 +4743,19 @@ class MPhi MOZ_FINAL : public MDefinitio
     bool specialized_;
     uint32_t capacity_;
 #endif
 
   protected:
     MUse *getUseFor(size_t index) {
         return &inputs_[index];
     }
+    const MUse *getUseFor(size_t index) const {
+        return &inputs_[index];
+    }
 
   public:
     INSTRUCTION_HEADER(Phi)
 
     MPhi(TempAllocator &alloc, MIRType resultType)
       : inputs_(alloc),
         hasBackedgeType_(false),
         triedToSpecialize_(false),
@@ -4737,28 +4775,33 @@ class MPhi MOZ_FINAL : public MDefinitio
     }
 
     void setOperand(size_t index, MDefinition *operand) {
         // Note: after the initial IonBuilder pass, it is OK to change phi
         // operands such that they do not include the type sets of their
         // operands. This can arise during e.g. value numbering, where
         // definitions producing the same value may have different type sets.
         JS_ASSERT(index < numOperands());
-        inputs_[index].set(operand, this, index);
+        inputs_[index].set(operand, this);
         operand->addUse(&inputs_[index]);
     }
 
     void removeOperand(size_t index);
 
     MDefinition *getOperand(size_t index) const {
         return inputs_[index].producer();
     }
     size_t numOperands() const {
         return inputs_.length();
     }
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        MOZ_ASSERT(u >= &inputs_[0]);
+        MOZ_ASSERT(u <= &inputs_[numOperands() - 1]);
+        return u - &inputs_[0];
+    }
     bool hasBackedgeType() const {
         return hasBackedgeType_;
     }
     bool triedToSpecialize() const {
         return triedToSpecialize_;
     }
     void specialize(MIRType type) {
         triedToSpecialize_ = true;
@@ -6717,17 +6760,17 @@ class MStoreTypedArrayElement
         return racy_;
     }
     void setRacy() {
         racy_ = true;
     }
     TruncateKind operandTruncateKind(size_t index) const;
 
     bool canConsumeFloat32(MUse *use) const {
-        return use->index() == 2 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
+        return use == getUseFor(2) && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
     }
 };
 
 class MStoreTypedArrayElementHole
   : public MAryInstruction<4>,
     public StoreTypedArrayHolePolicy
 {
     int arrayType_;
@@ -6785,17 +6828,17 @@ class MStoreTypedArrayElementHole
         return getOperand(3);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::TypedArrayElement);
     }
     TruncateKind operandTruncateKind(size_t index) const;
 
     bool canConsumeFloat32(MUse *use) const {
-        return use->index() == 3 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
+        return use == getUseFor(3) && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
     }
 };
 
 // Store a value infallibly to a statically known typed array.
 class MStoreTypedArrayElementStatic :
     public MBinaryInstruction
   , public StoreTypedArrayElementStaticPolicy
 {
@@ -6832,17 +6875,17 @@ class MStoreTypedArrayElementStatic :
     MDefinition *ptr() const { return getOperand(0); }
     MDefinition *value() const { return getOperand(1); }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::TypedArrayElement);
     }
     TruncateKind operandTruncateKind(size_t index) const;
 
     bool canConsumeFloat32(MUse *use) const {
-        return use->index() == 1 && typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32;
+        return use == getUseFor(1) && typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32;
     }
 };
 
 // Compute an "effective address", i.e., a compound computation of the form:
 //   base + index * scale + displacement
 class MEffectiveAddress : public MBinaryInstruction
 {
     MEffectiveAddress(MDefinition *base, MDefinition *index, Scale scale, int32_t displacement)
@@ -7343,30 +7386,38 @@ class MDispatchInstruction
       : map_(alloc), fallback_(nullptr)
     {
         setOperand(0, input);
     }
 
   protected:
     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
         JS_ASSERT(index == 0);
-        operand_.set(operand, this, 0);
+        operand_.set(operand, this);
         operand->addUse(&operand_);
     }
     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
         JS_ASSERT(index == 0);
         return &operand_;
     }
+    const MUse *getUseFor(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
+        JS_ASSERT(index == 0);
+        return &operand_;
+    }
     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
         JS_ASSERT(index == 0);
         return operand_.producer();
     }
     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
         return 1;
     }
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        JS_ASSERT(u == getUseFor(0));
+        return 0;
+    }
 
   public:
     void setSuccessor(size_t i, MBasicBlock *successor) {
         JS_ASSERT(i < numSuccessors());
         if (i == map_.length())
             fallback_ = successor;
         else
             map_[i].block = successor;
@@ -8294,17 +8345,17 @@ class MSetElementCache
     bool guardHoles() const {
         return guardHoles_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool canConsumeFloat32(MUse *use) const { return use->index() == 2; }
+    bool canConsumeFloat32(MUse *use) const { return use == getUseFor(2); }
 };
 
 class MCallGetProperty
   : public MUnaryInstruction,
     public BoxInputsPolicy
 {
     CompilerRootPropertyName name_;
     bool idempotent_;
@@ -9401,17 +9452,17 @@ class MPostWriteBarrier : public MBinary
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
 #ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         // During lowering, values that neither have object nor value MIR type
         // are ignored, thus Float32 can show up at this point without any issue.
-        return use->index() == 1;
+        return use == getUseFor(1);
     }
 #endif
 };
 
 class MNewDeclEnvObject : public MNullaryInstruction
 {
     CompilerRootObject templateObj_;
 
@@ -9695,41 +9746,49 @@ class MResumePoint MOZ_FINAL : public MN
         return operands_.init(alloc, stackDepth_);
     }
 
     // Overwrites an operand without updating its Uses.
     void setOperand(size_t index, MDefinition *operand) {
         JS_ASSERT(index < stackDepth_);
         // Note: We do not remove the isObserved flag, as this would imply that
         // we check the list of uses of the removed MDefinition.
-        operands_[index].set(operand, this, index);
+        operands_[index].set(operand, this);
         operand->addUse(&operands_[index]);
         if (!operand->isObserved() && isObservableOperand(index))
             operand->setObserved();
     }
 
     void clearOperand(size_t index) {
         JS_ASSERT(index < stackDepth_);
-        operands_[index].set(nullptr, this, index);
+        operands_[index].set(nullptr, this);
     }
 
     MUse *getUseFor(size_t index) {
         return &operands_[index];
     }
+    const MUse *getUseFor(size_t index) const {
+        return &operands_[index];
+    }
 
   public:
     static MResumePoint *New(TempAllocator &alloc, MBasicBlock *block, jsbytecode *pc,
                              MResumePoint *parent, Mode mode);
 
     MNode::Kind kind() const {
         return MNode::ResumePoint;
     }
     size_t numOperands() const {
         return stackDepth_;
     }
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        MOZ_ASSERT(u >= &operands_[0]);
+        MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
+        return u - &operands_[0];
+    }
 
     bool isObservableOperand(size_t index) const;
 
     MDefinition *getOperand(size_t index) const {
         JS_ASSERT(index < stackDepth_);
         MOZ_ASSERT_IF(isObservableOperand(index), operands_[index].producer()->isObserved());
         return operands_[index].producer();
     }
@@ -10192,22 +10251,25 @@ class MAsmJSCall MOZ_FINAL : public MIns
     size_t spIncrement_;
 
     MAsmJSCall(const CallSiteDesc &desc, Callee callee, size_t spIncrement)
      : desc_(desc), callee_(callee), spIncrement_(spIncrement)
     { }
 
   protected:
     void setOperand(size_t index, MDefinition *operand) {
-        operands_[index].set(operand, this, index);
+        operands_[index].set(operand, this);
         operand->addUse(&operands_[index]);
     }
     MUse *getUseFor(size_t index) {
         return &operands_[index];
     }
+    const MUse *getUseFor(size_t index) const {
+        return &operands_[index];
+    }
 
   public:
     INSTRUCTION_HEADER(AsmJSCall);
 
     struct Arg {
         AnyRegister reg;
         MDefinition *def;
         Arg(AnyRegister reg, MDefinition *def) : reg(reg), def(def) {}
@@ -10215,16 +10277,21 @@ class MAsmJSCall MOZ_FINAL : public MIns
     typedef Vector<Arg, 8> Args;
 
     static MAsmJSCall *New(TempAllocator &alloc, const CallSiteDesc &desc, Callee callee,
                            const Args &args, MIRType resultType, size_t spIncrement);
 
     size_t numOperands() const {
         return operands_.length();
     }
+    size_t indexOf(const MUse *u) const MOZ_FINAL MOZ_OVERRIDE {
+        MOZ_ASSERT(u >= &operands_[0]);
+        MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
+        return u - &operands_[0];
+    }
     MDefinition *getOperand(size_t index) const {
         JS_ASSERT(index < numOperands());
         return operands_[index].producer();
     }
     size_t numArgs() const {
         return argRegs_.length();
     }
     AnyRegister registerForArg(size_t index) const {
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -93,18 +93,20 @@ using JS::GenericNaN;
 // encounter beta nodes.
 
 static bool
 IsDominatedUse(MBasicBlock *block, MUse *use)
 {
     MNode *n = use->consumer();
     bool isPhi = n->isDefinition() && n->toDefinition()->isPhi();
 
-    if (isPhi)
-        return block->dominates(n->block()->getPredecessor(use->index()));
+    if (isPhi) {
+        MPhi *phi = n->toDefinition()->toPhi();
+        return block->dominates(phi->block()->getPredecessor(phi->indexOf(use)));
+    }
 
     return block->dominates(n->block());
 }
 
 static inline void
 SpewRange(MDefinition *def)
 {
 #ifdef DEBUG
@@ -2421,17 +2423,17 @@ ComputeRequestedTruncateKind(MInstructio
             // value, and any bailout with a truncated value might lead an
             // incorrect value.
             if (candidate->isUseRemoved() && needsConversion)
                 kind = Min(kind, MDefinition::TruncateAfterBailouts);
             continue;
         }
 
         MDefinition *consumer = use->consumer()->toDefinition();
-        MDefinition::TruncateKind consumerKind = consumer->operandTruncateKind(use->index());
+        MDefinition::TruncateKind consumerKind = consumer->operandTruncateKind(consumer->indexOf(*use));
         kind = Min(kind, consumerKind);
         if (kind == MDefinition::NoTruncate)
             break;
     }
 
     return kind;
 }