Bug 1488551 - Create NumberOperandId to make some number operations in CacheIRWriter/CacheIRCompiler more type safe. r=mgaudet
authorTetsuharu OHZEKI <tetsuharu.ohzeki@gmail.com>
Wed, 25 Sep 2019 21:49:33 +0000
changeset 494983 7a5339ab7cb77e57bea6f9c246a33ece4879df8d
parent 494982 4975f8c1003bf6a71844573954fde121abdd8b8b
child 494984 16bba4255fff3cc6b10f43fb82d6d5e126509077
push id114131
push userdluca@mozilla.com
push dateThu, 26 Sep 2019 09:47:34 +0000
treeherdermozilla-inbound@1dc1a755079a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmgaudet
bugs1488551
milestone71.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 1488551 - Create NumberOperandId to make some number operations in CacheIRWriter/CacheIRCompiler more type safe. r=mgaudet This changes: 1. Take `NumberOperandId` at the part which can use the result of `CacheIRWriter.guardIsNumber()`. 2. Use `NumberOperandId` as a function signature which would only take a number operand. * There are some exceptions, i.e.`CacheIRWriter.writer.truncateDoubleToUInt32()`, because `NumberOperandId` is not always `double`. Differential Revision: https://phabricator.services.mozilla.com/D46707
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CacheIRCompiler.h
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -5614,19 +5614,19 @@ AttachDecision CompareIRGenerator::tryAt
 }
 
 AttachDecision CompareIRGenerator::tryAttachNumber(ValOperandId lhsId,
                                                    ValOperandId rhsId) {
   if (!lhsVal_.isNumber() || !rhsVal_.isNumber()) {
     return AttachDecision::NoAction;
   }
 
-  writer.guardIsNumber(lhsId);
-  writer.guardIsNumber(rhsId);
-  writer.compareDoubleResult(op_, lhsId, rhsId);
+  NumberOperandId lhs = writer.guardIsNumber(lhsId);
+  NumberOperandId rhs = writer.guardIsNumber(rhsId);
+  writer.compareDoubleResult(op_, lhs, rhs);
   writer.returnFromIC();
 
   trackAttached("Number");
   return AttachDecision::Attach;
 }
 
 AttachDecision CompareIRGenerator::tryAttachObjectUndefined(
     ValOperandId lhsId, ValOperandId rhsId) {
@@ -5653,20 +5653,27 @@ AttachDecision CompareIRGenerator::tryAt
 // Handle NumberUndefined comparisons
 AttachDecision CompareIRGenerator::tryAttachNumberUndefined(
     ValOperandId lhsId, ValOperandId rhsId) {
   if (!(lhsVal_.isUndefined() && rhsVal_.isNumber()) &&
       !(rhsVal_.isUndefined() && lhsVal_.isNumber())) {
     return AttachDecision::NoAction;
   }
 
-  lhsVal_.isNumber() ? writer.guardIsNumber(lhsId)
-                     : writer.guardIsUndefined(lhsId);
-  rhsVal_.isNumber() ? writer.guardIsNumber(rhsId)
-                     : writer.guardIsUndefined(rhsId);
+  if (lhsVal_.isNumber()) {
+    writer.guardIsNumber(lhsId);
+  } else {
+    writer.guardIsUndefined(lhsId);
+  }
+
+  if (rhsVal_.isNumber()) {
+    writer.guardIsNumber(rhsId);
+  } else {
+    writer.guardIsUndefined(rhsId);
+  }
 
   // Comparing a number with undefined will always be true for NE/STRICTNE,
   // and always be false for other compare ops.
   writer.loadBooleanResult(op_ == JSOP_NE || op_ == JSOP_STRICTNE);
   writer.returnFromIC();
 
   trackAttached("NumberUndefined");
   return AttachDecision::Attach;
@@ -5769,22 +5776,22 @@ AttachDecision CompareIRGenerator::tryAt
   MOZ_ASSERT(op_ != JSOP_STRICTEQ && op_ != JSOP_STRICTNE);
 
   auto createGuards = [&](HandleValue v, ValOperandId vId) {
     if (v.isString()) {
       StringOperandId strId = writer.guardToString(vId);
       return writer.guardAndGetNumberFromString(strId);
     }
     MOZ_ASSERT(v.isNumber());
-    writer.guardIsNumber(vId);
-    return vId;
+    NumberOperandId numId = writer.guardIsNumber(vId);
+    return numId;
   };
 
-  ValOperandId lhsGuardedId = createGuards(lhsVal_, lhsId);
-  ValOperandId rhsGuardedId = createGuards(rhsVal_, rhsId);
+  NumberOperandId lhsGuardedId = createGuards(lhsVal_, lhsId);
+  NumberOperandId rhsGuardedId = createGuards(rhsVal_, rhsId);
   writer.compareDoubleResult(op_, lhsGuardedId, rhsGuardedId);
   writer.returnFromIC();
 
   trackAttached("StringNumber");
   return AttachDecision::Attach;
 }
 
 AttachDecision CompareIRGenerator::tryAttachStub() {
@@ -6043,34 +6050,34 @@ AttachDecision UnaryArithIRGenerator::tr
 }
 
 AttachDecision UnaryArithIRGenerator::tryAttachNumber() {
   if (!val_.isNumber() || !res_.isNumber()) {
     return AttachDecision::NoAction;
   }
 
   ValOperandId valId(writer.setInputOperandId(0));
-  writer.guardIsNumber(valId);
+  NumberOperandId numId = writer.guardIsNumber(valId);
   Int32OperandId truncatedId;
   switch (op_) {
     case JSOP_BITNOT:
-      truncatedId = writer.truncateDoubleToUInt32(valId);
+      truncatedId = writer.truncateDoubleToUInt32(numId);
       writer.int32NotResult(truncatedId);
       trackAttached("UnaryArith.DoubleNot");
       break;
     case JSOP_NEG:
-      writer.doubleNegationResult(valId);
+      writer.doubleNegationResult(numId);
       trackAttached("UnaryArith.DoubleNeg");
       break;
     case JSOP_INC:
-      writer.doubleIncResult(valId);
+      writer.doubleIncResult(numId);
       trackAttached("UnaryArith.DoubleInc");
       break;
     case JSOP_DEC:
-      writer.doubleDecResult(valId);
+      writer.doubleDecResult(numId);
       trackAttached("UnaryArith.DoubleDec");
       break;
     default:
       MOZ_CRASH("Unexpected OP");
   }
 
   writer.returnFromIC();
   return AttachDecision::Attach;
@@ -6201,38 +6208,38 @@ AttachDecision BinaryArithIRGenerator::t
   // Check guard conditions
   if (!lhs_.isNumber() || !rhs_.isNumber()) {
     return AttachDecision::NoAction;
   }
 
   ValOperandId lhsId(writer.setInputOperandId(0));
   ValOperandId rhsId(writer.setInputOperandId(1));
 
-  writer.guardIsNumber(lhsId);
-  writer.guardIsNumber(rhsId);
+  NumberOperandId lhs = writer.guardIsNumber(lhsId);
+  NumberOperandId rhs = writer.guardIsNumber(rhsId);
 
   switch (op_) {
     case JSOP_ADD:
-      writer.doubleAddResult(lhsId, rhsId);
+      writer.doubleAddResult(lhs, rhs);
       trackAttached("BinaryArith.Double.Add");
       break;
     case JSOP_SUB:
-      writer.doubleSubResult(lhsId, rhsId);
+      writer.doubleSubResult(lhs, rhs);
       trackAttached("BinaryArith.Double.Sub");
       break;
     case JSOP_MUL:
-      writer.doubleMulResult(lhsId, rhsId);
+      writer.doubleMulResult(lhs, rhs);
       trackAttached("BinaryArith.Double.Mul");
       break;
     case JSOP_DIV:
-      writer.doubleDivResult(lhsId, rhsId);
+      writer.doubleDivResult(lhs, rhs);
       trackAttached("BinaryArith.Double.Div");
       break;
     case JSOP_MOD:
-      writer.doubleModResult(lhsId, rhsId);
+      writer.doubleModResult(lhs, rhs);
       trackAttached("BinaryArith.Double.Mod");
       break;
     default:
       MOZ_CRASH("Unhandled Op");
   }
   writer.returnFromIC();
   return AttachDecision::Attach;
 }
@@ -6318,18 +6325,18 @@ AttachDecision BinaryArithIRGenerator::t
     }
     if (v.isInt32()) {
       Int32OperandId intId = writer.guardToInt32(id);
       return writer.callInt32ToString(intId);
     }
     // At this point we are creating an IC that will handle
     // both Int32 and Double cases.
     MOZ_ASSERT(v.isNumber());
-    writer.guardIsNumber(id);
-    return writer.callNumberToString(id);
+    NumberOperandId numId = writer.guardIsNumber(id);
+    return writer.callNumberToString(numId);
   };
 
   StringOperandId lhsStrId = guardToString(lhsId, lhs_);
   StringOperandId rhsStrId = guardToString(rhsId, rhs_);
 
   writer.callStringConcatResult(lhsStrId, rhsStrId);
 
   writer.returnFromIC();
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -93,16 +93,22 @@ class ObjOperandId : public OperandId {
  public:
   ObjOperandId() = default;
   explicit ObjOperandId(uint16_t id) : OperandId(id) {}
 
   bool operator==(const ObjOperandId& other) const { return id_ == other.id_; }
   bool operator!=(const ObjOperandId& other) const { return id_ != other.id_; }
 };
 
+class NumberOperandId : public ValOperandId {
+ public:
+  NumberOperandId() = default;
+  explicit NumberOperandId(uint16_t id) : ValOperandId(id) {}
+};
+
 class StringOperandId : public OperandId {
  public:
   StringOperandId() = default;
   explicit StringOperandId(uint16_t id) : OperandId(id) {}
 };
 
 class SymbolOperandId : public OperandId {
  public:
@@ -123,16 +129,18 @@ class Int32OperandId : public OperandId 
 };
 
 class TypedOperandId : public OperandId {
   JSValueType type_;
 
  public:
   MOZ_IMPLICIT TypedOperandId(ObjOperandId id)
       : OperandId(id.id()), type_(JSVAL_TYPE_OBJECT) {}
+  MOZ_IMPLICIT TypedOperandId(NumberOperandId id)
+      : OperandId(id.id()), type_(JSVAL_TYPE_OBJECT) {}
   MOZ_IMPLICIT TypedOperandId(StringOperandId id)
       : OperandId(id.id()), type_(JSVAL_TYPE_STRING) {}
   MOZ_IMPLICIT TypedOperandId(SymbolOperandId id)
       : OperandId(id.id()), type_(JSVAL_TYPE_SYMBOL) {}
   MOZ_IMPLICIT TypedOperandId(BigIntOperandId id)
       : OperandId(id.id()), type_(JSVAL_TYPE_BIGINT) {}
   MOZ_IMPLICIT TypedOperandId(Int32OperandId id)
       : OperandId(id.id()), type_(JSVAL_TYPE_INT32) {}
@@ -839,18 +847,19 @@ class MOZ_RAII CacheIRWriter : public JS
 
   Int32OperandId guardToInt32Index(ValOperandId val) {
     Int32OperandId res(nextOperandId_++);
     writeOpWithOperandId(CacheOp::GuardToInt32Index, val);
     writeOperandId(res);
     return res;
   }
 
-  void guardIsNumber(ValOperandId val) {
+  NumberOperandId guardIsNumber(ValOperandId val) {
     writeOpWithOperandId(CacheOp::GuardIsNumber, val);
+    return NumberOperandId(val.id());
   }
 
   void guardType(ValOperandId val, ValueType type) {
     writeOpWithOperandId(CacheOp::GuardType, val);
     static_assert(sizeof(type) == sizeof(uint8_t),
                   "JS::ValueType should fit in a byte");
     buffer_.writeByte(uint32_t(type));
   }
@@ -1062,18 +1071,18 @@ class MOZ_RAII CacheIRWriter : public JS
 
   Int32OperandId guardAndGetIndexFromString(StringOperandId str) {
     Int32OperandId res(nextOperandId_++);
     writeOpWithOperandId(CacheOp::GuardAndGetIndexFromString, str);
     writeOperandId(res);
     return res;
   }
 
-  ValOperandId guardAndGetNumberFromString(StringOperandId str) {
-    ValOperandId res(nextOperandId_++);
+  NumberOperandId guardAndGetNumberFromString(StringOperandId str) {
+    NumberOperandId res(nextOperandId_++);
     writeOpWithOperandId(CacheOp::GuardAndGetNumberFromString, str);
     writeOperandId(res);
     return res;
   }
 
   ObjOperandId guardAndGetIterator(ObjOperandId obj,
                                    PropertyIteratorObject* iter,
                                    NativeIterator** enumeratorsAddr) {
@@ -1401,17 +1410,17 @@ class MOZ_RAII CacheIRWriter : public JS
 
   StringOperandId callInt32ToString(Int32OperandId id) {
     StringOperandId res(nextOperandId_++);
     writeOpWithOperandId(CacheOp::CallInt32ToString, id);
     writeOperandId(res);
     return res;
   }
 
-  StringOperandId callNumberToString(ValOperandId id) {
+  StringOperandId callNumberToString(NumberOperandId id) {
     StringOperandId res(nextOperandId_++);
     writeOpWithOperandId(CacheOp::CallNumberToString, id);
     writeOperandId(res);
     return res;
   }
 
   StringOperandId booleanToString(Int32OperandId id) {
     StringOperandId res(nextOperandId_++);
@@ -1556,37 +1565,37 @@ class MOZ_RAII CacheIRWriter : public JS
 
   void megamorphicHasPropResult(ObjOperandId obj, ValOperandId id,
                                 bool hasOwn) {
     writeOpWithOperandId(CacheOp::MegamorphicHasPropResult, obj);
     writeOperandId(id);
     buffer_.writeByte(uint32_t(hasOwn));
   }
 
-  void doubleAddResult(ValOperandId lhsId, ValOperandId rhsId) {
+  void doubleAddResult(NumberOperandId lhsId, NumberOperandId rhsId) {
     writeOpWithOperandId(CacheOp::DoubleAddResult, lhsId);
     writeOperandId(rhsId);
   }
 
-  void doubleSubResult(ValOperandId lhsId, ValOperandId rhsId) {
+  void doubleSubResult(NumberOperandId lhsId, NumberOperandId rhsId) {
     writeOpWithOperandId(CacheOp::DoubleSubResult, lhsId);
     writeOperandId(rhsId);
   }
 
-  void doubleMulResult(ValOperandId lhsId, ValOperandId rhsId) {
+  void doubleMulResult(NumberOperandId lhsId, NumberOperandId rhsId) {
     writeOpWithOperandId(CacheOp::DoubleMulResult, lhsId);
     writeOperandId(rhsId);
   }
 
-  void doubleDivResult(ValOperandId lhsId, ValOperandId rhsId) {
+  void doubleDivResult(NumberOperandId lhsId, NumberOperandId rhsId) {
     writeOpWithOperandId(CacheOp::DoubleDivResult, lhsId);
     writeOperandId(rhsId);
   }
 
-  void doubleModResult(ValOperandId lhsId, ValOperandId rhsId) {
+  void doubleModResult(NumberOperandId lhsId, NumberOperandId rhsId) {
     writeOpWithOperandId(CacheOp::DoubleModResult, lhsId);
     writeOperandId(rhsId);
   }
 
   void int32AddResult(Int32OperandId lhs, Int32OperandId rhs) {
     writeOpWithOperandId(CacheOp::Int32AddResult, lhs);
     writeOperandId(rhs);
   }
@@ -1654,25 +1663,25 @@ class MOZ_RAII CacheIRWriter : public JS
   void int32IncResult(Int32OperandId id) {
     writeOpWithOperandId(CacheOp::Int32IncResult, id);
   }
 
   void int32DecResult(Int32OperandId id) {
     writeOpWithOperandId(CacheOp::Int32DecResult, id);
   }
 
-  void doubleNegationResult(ValOperandId val) {
+  void doubleNegationResult(NumberOperandId val) {
     writeOpWithOperandId(CacheOp::DoubleNegationResult, val);
   }
 
-  void doubleIncResult(ValOperandId val) {
+  void doubleIncResult(NumberOperandId val) {
     writeOpWithOperandId(CacheOp::DoubleIncResult, val);
   }
 
-  void doubleDecResult(ValOperandId val) {
+  void doubleDecResult(NumberOperandId val) {
     writeOpWithOperandId(CacheOp::DoubleDecResult, val);
   }
 
   void loadBooleanResult(bool val) {
     writeOp(CacheOp::LoadBooleanResult);
     buffer_.writeByte(uint32_t(val));
   }
 
@@ -1916,17 +1925,18 @@ class MOZ_RAII CacheIRWriter : public JS
   }
 
   void compareInt32Result(uint32_t op, Int32OperandId lhs, Int32OperandId rhs) {
     writeOpWithOperandId(CacheOp::CompareInt32Result, lhs);
     writeOperandId(rhs);
     buffer_.writeByte(uint32_t(op));
   }
 
-  void compareDoubleResult(uint32_t op, ValOperandId lhs, ValOperandId rhs) {
+  void compareDoubleResult(uint32_t op, NumberOperandId lhs,
+                           NumberOperandId rhs) {
     writeOpWithOperandId(CacheOp::CompareDoubleResult, lhs);
     writeOperandId(rhs);
     buffer_.writeByte(uint32_t(op));
   }
 
   void callPrintString(const char* str) {
     writeOp(CacheOp::CallPrintString);
     writePointer(const_cast<char*>(str));
@@ -1967,16 +1977,19 @@ class MOZ_RAII CacheIRReader {
   }
 
   ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
   ValueTagOperandId valueTagOperandId() {
     return ValueTagOperandId(buffer_.readByte());
   }
 
   ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
+  NumberOperandId numberOperandId() {
+    return NumberOperandId(buffer_.readByte());
+  }
   StringOperandId stringOperandId() {
     return StringOperandId(buffer_.readByte());
   }
 
   SymbolOperandId symbolOperandId() {
     return SymbolOperandId(buffer_.readByte());
   }
 
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -98,17 +98,17 @@ ValueOperand CacheRegisterAllocator::use
   }
 
   MOZ_CRASH();
 }
 
 // Load a value operand directly into a float register. Caller must have
 // guarded isNumber on the provided val.
 void CacheRegisterAllocator::ensureDoubleRegister(MacroAssembler& masm,
-                                                  ValOperandId op,
+                                                  NumberOperandId op,
                                                   FloatRegister dest) {
   OperandLocation& loc = operandLocations_[op.id()];
 
   Label failure, done;
   switch (loc.kind()) {
     case OperandLocation::ValueReg: {
       masm.ensureDouble(loc.valueReg(), dest, &failure);
       break;
@@ -2110,67 +2110,67 @@ bool CacheIRCompiler::emitLoadInt32Array
 
 bool CacheIRCompiler::emitDoubleAddResult() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoOutputRegister output(*this);
 
   // Float register must be preserved. The BinaryArith ICs use
   // the fact that baseline has them available, as well as fixed temps on
   // LBinaryCache.
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg0);
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg1);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg1);
 
   masm.addDouble(FloatReg1, FloatReg0);
   masm.boxDouble(FloatReg0, output.valueReg(), FloatReg0);
 
   return true;
 }
 bool CacheIRCompiler::emitDoubleSubResult() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoOutputRegister output(*this);
 
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg0);
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg1);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg1);
 
   masm.subDouble(FloatReg1, FloatReg0);
   masm.boxDouble(FloatReg0, output.valueReg(), FloatReg0);
 
   return true;
 }
 bool CacheIRCompiler::emitDoubleMulResult() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoOutputRegister output(*this);
 
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg0);
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg1);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg1);
 
   masm.mulDouble(FloatReg1, FloatReg0);
   masm.boxDouble(FloatReg0, output.valueReg(), FloatReg0);
 
   return true;
 }
 bool CacheIRCompiler::emitDoubleDivResult() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoOutputRegister output(*this);
 
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg0);
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg1);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg1);
 
   masm.divDouble(FloatReg1, FloatReg0);
   masm.boxDouble(FloatReg0, output.valueReg(), FloatReg0);
 
   return true;
 }
 bool CacheIRCompiler::emitDoubleModResult() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoOutputRegister output(*this);
   AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
 
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg0);
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg1);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg1);
 
   LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
   masm.PushRegsInMask(save);
 
   masm.setupUnalignedABICall(scratch);
   masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
   masm.passABIArg(FloatReg1, MoveOp::DOUBLE);
   masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::NumberMod), MoveOp::DOUBLE);
@@ -3629,18 +3629,18 @@ bool CacheIRCompiler::emitCompareDoubleR
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoOutputRegister output(*this);
 
   FailurePath* failure;
   if (!addFailurePath(&failure)) {
     return false;
   }
 
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg0);
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg1);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg1);
   JSOp op = reader.jsop();
 
   Label done, ifTrue;
   masm.branchDouble(JSOpToDoubleCondition(op), FloatReg0, FloatReg1, &ifTrue);
   EmitStoreBoolean(masm, false, output);
   masm.jump(&done);
 
   masm.bind(&ifTrue);
@@ -4262,17 +4262,17 @@ bool CacheIRCompiler::emitCallInt32ToStr
   return true;
 }
 
 bool CacheIRCompiler::emitCallNumberToString() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   // Float register must be preserved. The BinaryArith ICs use
   // the fact that baseline has them available, as well as fixed temps on
   // LBinaryCache.
-  allocator.ensureDoubleRegister(masm, reader.valOperandId(), FloatReg0);
+  allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
   Register result = allocator.defineRegister(masm, reader.stringOperandId());
 
   FailurePath* failure;
   if (!addFailurePath(&failure)) {
     return false;
   }
 
   LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(),
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -600,17 +600,18 @@ class MOZ_RAII CacheRegisterAllocator {
 
   // Allocates an output register for the given operand.
   Register defineRegister(MacroAssembler& masm, TypedOperandId typedId);
   ValueOperand defineValueRegister(MacroAssembler& masm, ValOperandId val);
 
   // Loads (potentially coercing) and unboxes a value into a float register
   // This is infallible, as there should have been a previous guard
   // to ensure the ValOperandId is already a number.
-  void ensureDoubleRegister(MacroAssembler&, ValOperandId, FloatRegister);
+  void ensureDoubleRegister(MacroAssembler& masm, NumberOperandId op,
+                            FloatRegister dest);
 
   // Returns |val|'s JSValueType or JSVAL_TYPE_UNKNOWN.
   JSValueType knownType(ValOperandId val) const;
 
   // Emits code to restore registers and stack to the state at the start of
   // the stub.
   void restoreInputState(MacroAssembler& masm, bool discardStack = true);