Bug 1574415 - Part 9: Move emitStoreTypedElement into CacheIRCompiler. r=jandem
authorAndré Bargull <andre.bargull@gmail.com>
Mon, 07 Oct 2019 11:59:10 +0000
changeset 496561 3601bf7917332395df032c833f9903e826ead8e9
parent 496560 6eead2ab3379aa4818ca3e6d4fc228ade46d4296
child 496562 42469f1d04913311bd96876eb106a8fba39d2223
push id97326
push userarchaeopteryx@coole-files.de
push dateMon, 07 Oct 2019 16:46:32 +0000
treeherderautoland@144ebbca6844 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1574415
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 1574415 - Part 9: Move emitStoreTypedElement into CacheIRCompiler. r=jandem Changes `LSetPropertyCache` to use `Float0` as a fixed temporary register, which makes it easier to share the implementation between Baseline and Ion. Additionally this fixes a TypedObject bug where `Float0` was clobbered, see the regression test in part 11. Also adds support for `Constant`, `PayloadReg`, and `PayloadStack` operand locations to `CacheRegisterAllocator::ensureDoubleRegister`, which are now needed because the right-hand side in TypedArray assignments can be constants resp. values in payload registers or on the stack. Differential Revision: https://phabricator.services.mozilla.com/D47757
js/src/jit-test/tests/cacheir/store-typed-element-constant-double-rhs.js
js/src/jit-test/tests/cacheir/store-typed-element-payload-reg-rhs.js
js/src/jit-test/tests/cacheir/store-typed-element-payload-stack-rhs.js
js/src/jit/BaselineCacheIRCompiler.cpp
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CacheIRCompiler.h
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonCacheIRCompiler.cpp
js/src/jit/IonIC.h
js/src/jit/Lowering.cpp
js/src/jit/shared/LIR-shared.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/cacheir/store-typed-element-constant-double-rhs.js
@@ -0,0 +1,15 @@
+// Different typed array types to ensure we emit a SetProp IC.
+var xs = [
+  new Float32Array(10),
+  new Float64Array(10),
+];
+
+for (var i = 0; i < 100; ++i) {
+  var ta = xs[i & 1];
+
+  // Store with constant rhs.
+  ta[0] = 0.1;
+}
+
+assertEq(xs[0][0], Math.fround(0.1));
+assertEq(xs[1][0], 0.1);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/cacheir/store-typed-element-payload-reg-rhs.js
@@ -0,0 +1,17 @@
+// Different typed array types to ensure we emit a SetProp IC.
+var xs = [
+  new Float32Array(10),
+  new Float64Array(10),
+];
+
+for (var i = 0; i < 100; ++i) {
+  var ta = xs[i & 1];
+
+  var v = +ta[0];
+
+  // Store with payload-register rhs.
+  ta[0] = ~v;
+}
+
+assertEq(xs[0][0], 0);
+assertEq(xs[1][0], 0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/cacheir/store-typed-element-payload-stack-rhs.js
@@ -0,0 +1,20 @@
+// Different typed array types to ensure we emit a SetProp IC.
+var xs = [
+  new Float32Array(10),
+  new Float64Array(10),
+];
+
+function f(ta) {
+  for (var k = 0;;) {
+    // Store with payload-stack rhs.
+    ta[k] = k;
+    break;
+  }
+}
+
+for (var i = 0; i < 100; ++i) {
+  f(xs[i & 1]);
+}
+
+assertEq(xs[0][0], 0);
+assertEq(xs[1][0], 0);
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -1440,88 +1440,16 @@ bool BaselineCacheIRCompiler::emitArrayP
 
   // Return value is new length.
   masm.add32(Imm32(1), scratchLength);
   masm.tagValue(JSVAL_TYPE_INT32, scratchLength, val);
 
   return true;
 }
 
-bool BaselineCacheIRCompiler::emitStoreTypedElement() {
-  JitSpew(JitSpew_Codegen, __FUNCTION__);
-  Register obj = allocator.useRegister(masm, reader.objOperandId());
-  TypedThingLayout layout = reader.typedThingLayout();
-  Scalar::Type type = reader.scalarType();
-  Register index = allocator.useRegister(masm, reader.int32OperandId());
-
-  Maybe<Register> valInt32;
-  Maybe<NumberOperandId> valFloat;
-  switch (type) {
-    case Scalar::Int8:
-    case Scalar::Uint8:
-    case Scalar::Int16:
-    case Scalar::Uint16:
-    case Scalar::Int32:
-    case Scalar::Uint32:
-    case Scalar::Uint8Clamped:
-      valInt32.emplace(allocator.useRegister(masm, reader.int32OperandId()));
-      break;
-
-    case Scalar::Float32:
-    case Scalar::Float64:
-      valFloat.emplace(reader.numberOperandId());
-      break;
-
-    case Scalar::BigInt64:
-    case Scalar::BigUint64:
-    case Scalar::MaxTypedArrayViewType:
-    case Scalar::Int64:
-      MOZ_CRASH("Unsupported TypedArray type");
-  }
-
-  bool handleOOB = reader.readBool();
-
-  AutoScratchRegister scratch1(allocator, masm);
-  AutoScratchRegister scratch2(allocator, masm);
-
-  FailurePath* failure;
-  if (!addFailurePath(&failure)) {
-    return false;
-  }
-
-  // Bounds check.
-  Label done;
-  LoadTypedThingLength(masm, layout, obj, scratch1);
-
-  masm.spectreBoundsCheck32(index, scratch1, scratch2,
-                            handleOOB ? &done : failure->label());
-
-  // Load the elements vector.
-  LoadTypedThingData(masm, layout, obj, scratch1);
-
-  BaseIndex dest(scratch1, index, ScaleFromElemWidth(Scalar::byteSize(type)));
-
-  if (type == Scalar::Float32 || type == Scalar::Float64) {
-    allocator.ensureDoubleRegister(masm, *valFloat, FloatReg0);
-
-    if (type == Scalar::Float32) {
-      ScratchFloat32Scope fpscratch(masm);
-      masm.convertDoubleToFloat32(FloatReg0, fpscratch);
-      masm.storeToTypedFloatArray(type, fpscratch, dest);
-    } else {
-      masm.storeToTypedFloatArray(type, FloatReg0, dest);
-    }
-  } else {
-    masm.storeToTypedIntArray(type, *valInt32, dest);
-  }
-
-  masm.bind(&done);
-  return true;
-}
-
 bool BaselineCacheIRCompiler::emitCallNativeSetter() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   Register obj = allocator.useRegister(masm, reader.objOperandId());
   Address setterAddr(stubAddress(reader.stubOffset()));
   ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
 
   AutoScratchRegister scratch(allocator, masm);
 
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -128,19 +128,42 @@ void CacheRegisterAllocator::ensureDoubl
     }
 
     case OperandLocation::DoubleReg: {
       masm.moveDouble(loc.doubleReg(), dest);
       loc.setDoubleReg(dest);
       return;
     }
 
-    case OperandLocation::Constant:
-    case OperandLocation::PayloadStack:
-    case OperandLocation::PayloadReg:
+    case OperandLocation::Constant: {
+      MOZ_ASSERT(loc.constant().isNumber(),
+                 "Caller must ensure the operand is a number value");
+      masm.loadConstantDouble(loc.constant().toNumber(), dest);
+      return;
+    }
+
+    case OperandLocation::PayloadReg: {
+      // Doubles can't be stored in payload registers, so this must be an int32.
+      MOZ_ASSERT(loc.payloadType() == JSVAL_TYPE_INT32,
+                 "Caller must ensure the operand is a number value");
+      masm.convertInt32ToDouble(loc.payloadReg(), dest);
+      return;
+    }
+
+    case OperandLocation::PayloadStack: {
+      // Doubles can't be stored in payload registers, so this must be an int32.
+      MOZ_ASSERT(loc.payloadType() == JSVAL_TYPE_INT32,
+                 "Caller must ensure the operand is a number value");
+      MOZ_ASSERT(loc.payloadStack() <= stackPushed_);
+      masm.convertInt32ToDouble(
+          Address(masm.getStackPointer(), stackPushed_ - loc.payloadStack()),
+          dest);
+      return;
+    }
+
     case OperandLocation::Uninitialized:
       MOZ_CRASH("Unhandled operand type in ensureDoubleRegister");
       return;
   }
   masm.jump(&done);
   masm.bind(&failure);
   masm.assumeUnreachable(
       "Missing guard allowed non-number to hit ensureDoubleRegister");
@@ -3368,16 +3391,85 @@ bool CacheIRCompiler::emitArrayJoinResul
   // Store the value.
   masm.loadValue(elementAddr, output.valueReg());
 
   masm.bind(&finished);
 
   return true;
 }
 
+bool CacheIRCompiler::emitStoreTypedElement() {
+  JitSpew(JitSpew_Codegen, __FUNCTION__);
+  Register obj = allocator.useRegister(masm, reader.objOperandId());
+  TypedThingLayout layout = reader.typedThingLayout();
+  Scalar::Type type = reader.scalarType();
+  Register index = allocator.useRegister(masm, reader.int32OperandId());
+
+  Maybe<Register> valInt32;
+  switch (type) {
+    case Scalar::Int8:
+    case Scalar::Uint8:
+    case Scalar::Int16:
+    case Scalar::Uint16:
+    case Scalar::Int32:
+    case Scalar::Uint32:
+    case Scalar::Uint8Clamped:
+      valInt32.emplace(allocator.useRegister(masm, reader.int32OperandId()));
+      break;
+
+    case Scalar::Float32:
+    case Scalar::Float64:
+      // Float register must be preserved. The SetProp ICs use the fact that
+      // baseline has them available, as well as fixed temps on
+      // LSetPropertyCache.
+      allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0);
+      break;
+
+    case Scalar::BigInt64:
+    case Scalar::BigUint64:
+    case Scalar::MaxTypedArrayViewType:
+    case Scalar::Int64:
+      MOZ_CRASH("Unsupported TypedArray type");
+  }
+
+  bool handleOOB = reader.readBool();
+
+  AutoScratchRegister scratch1(allocator, masm);
+  AutoScratchRegister scratch2(allocator, masm);
+
+  FailurePath* failure;
+  if (!addFailurePath(&failure)) {
+    return false;
+  }
+
+  // Bounds check.
+  Label done;
+  LoadTypedThingLength(masm, layout, obj, scratch1);
+  masm.spectreBoundsCheck32(index, scratch1, scratch2,
+                            handleOOB ? &done : failure->label());
+
+  // Load the elements vector.
+  LoadTypedThingData(masm, layout, obj, scratch1);
+
+  BaseIndex dest(scratch1, index, ScaleFromElemWidth(Scalar::byteSize(type)));
+
+  if (type == Scalar::Float32) {
+    ScratchFloat32Scope fpscratch(masm);
+    masm.convertDoubleToFloat32(FloatReg0, fpscratch);
+    masm.storeToTypedFloatArray(type, fpscratch, dest);
+  } else if (type == Scalar::Float64) {
+    masm.storeToTypedFloatArray(type, FloatReg0, dest);
+  } else {
+    masm.storeToTypedIntArray(type, *valInt32, dest);
+  }
+
+  masm.bind(&done);
+  return true;
+}
+
 bool CacheIRCompiler::emitLoadTypedElementResult() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoOutputRegister output(*this);
   Register obj = allocator.useRegister(masm, reader.objOperandId());
   Register index = allocator.useRegister(masm, reader.int32OperandId());
   TypedThingLayout layout = reader.typedThingLayout();
   Scalar::Type type = reader.scalarType();
 
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -118,16 +118,17 @@ class IonCacheIRCompiler;
   _(LoadObjectTruthyResult)               \
   _(LoadNewObjectFromTemplateResult)      \
   _(CompareObjectResult)                  \
   _(CompareSymbolResult)                  \
   _(CompareInt32Result)                   \
   _(CompareDoubleResult)                  \
   _(CompareObjectUndefinedNullResult)     \
   _(ArrayJoinResult)                      \
+  _(StoreTypedElement)                    \
   _(CallPrintString)                      \
   _(Breakpoint)                           \
   _(MegamorphicLoadSlotResult)            \
   _(MegamorphicLoadSlotByValueResult)     \
   _(MegamorphicStoreSlot)                 \
   _(MegamorphicHasPropResult)             \
   _(CallObjectHasSparseElementResult)     \
   _(CallInt32ToString)                    \
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11202,30 +11202,28 @@ void CodeGenerator::addGetPropertyCache(
   }
   IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp,
                          resultFlags);
   addIC(ins, allocateIC(cache));
 }
 
 void CodeGenerator::addSetPropertyCache(
     LInstruction* ins, LiveRegisterSet liveRegs, Register objReg, Register temp,
-    FloatRegister tempDouble, FloatRegister tempF32,
     const ConstantOrRegister& id, const ConstantOrRegister& value, bool strict,
     bool needsPostBarrier, bool needsTypeBarrier, bool guardHoles) {
   CacheKind kind = CacheKind::SetElem;
   if (id.constant() && id.value().isString()) {
     JSString* idString = id.value().toString();
     uint32_t dummy;
     if (idString->isAtom() && !idString->asAtom().isIndex(&dummy)) {
       kind = CacheKind::SetProp;
     }
   }
-  IonSetPropertyIC cache(kind, liveRegs, objReg, temp, tempDouble, tempF32, id,
-                         value, strict, needsPostBarrier, needsTypeBarrier,
-                         guardHoles);
+  IonSetPropertyIC cache(kind, liveRegs, objReg, temp, id, value, strict,
+                         needsPostBarrier, needsTypeBarrier, guardHoles);
   addIC(ins, allocateIC(cache));
 }
 
 ConstantOrRegister CodeGenerator::toConstantOrRegister(LInstruction* lir,
                                                        size_t n, MIRType type) {
   if (type == MIRType::Value) {
     return TypedOrValueRegister(ToValue(lir, n));
   }
@@ -11393,27 +11391,24 @@ void CodeGenerator::visitCallDeleteEleme
     callVM<Fn, DeleteElementJit<false>>(lir);
   }
 }
 
 void CodeGenerator::visitSetPropertyCache(LSetPropertyCache* ins) {
   LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   Register objReg = ToRegister(ins->getOperand(0));
   Register temp = ToRegister(ins->temp());
-  FloatRegister tempDouble = ToTempFloatRegisterOrInvalid(ins->tempDouble());
-  FloatRegister tempF32 = ToTempFloatRegisterOrInvalid(ins->tempFloat32());
 
   ConstantOrRegister id = toConstantOrRegister(ins, LSetPropertyCache::Id,
                                                ins->mir()->idval()->type());
   ConstantOrRegister value = toConstantOrRegister(ins, LSetPropertyCache::Value,
                                                   ins->mir()->value()->type());
 
-  addSetPropertyCache(ins, liveRegs, objReg, temp, tempDouble, tempF32, id,
-                      value, ins->mir()->strict(),
-                      ins->mir()->needsPostBarrier(),
+  addSetPropertyCache(ins, liveRegs, objReg, temp, id, value,
+                      ins->mir()->strict(), ins->mir()->needsPostBarrier(),
                       ins->mir()->needsTypeBarrier(), ins->mir()->guardHoles());
 }
 
 void CodeGenerator::visitThrow(LThrow* lir) {
   pushArg(ToValue(lir, LThrow::Value));
 
   using Fn = bool (*)(JSContext*, HandleValue);
   callVM<Fn, js::ThrowOperation>(lir);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -238,17 +238,16 @@ class CodeGenerator final : public CodeG
 
   void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
                            TypedOrValueRegister value,
                            const ConstantOrRegister& id,
                            TypedOrValueRegister output, Register maybeTemp,
                            GetPropertyResultFlags flags);
   void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
                            Register objReg, Register temp,
-                           FloatRegister tempDouble, FloatRegister tempF32,
                            const ConstantOrRegister& id,
                            const ConstantOrRegister& value, bool strict,
                            bool needsPostBarrier, bool needsTypeBarrier,
                            bool guardHoles);
 
   MOZ_MUST_USE bool generateBranchV(const ValueOperand& value, Label* ifTrue,
                                     Label* ifFalse, FloatRegister fr);
 
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -1804,98 +1804,16 @@ bool IonCacheIRCompiler::emitStoreDenseE
   return true;
 }
 
 bool IonCacheIRCompiler::emitArrayPush() {
   MOZ_ASSERT_UNREACHABLE("emitArrayPush not supported for IonCaches.");
   return false;
 }
 
-bool IonCacheIRCompiler::emitStoreTypedElement() {
-  JitSpew(JitSpew_Codegen, __FUNCTION__);
-  Register obj = allocator.useRegister(masm, reader.objOperandId());
-  TypedThingLayout layout = reader.typedThingLayout();
-  Scalar::Type arrayType = reader.scalarType();
-  Register index = allocator.useRegister(masm, reader.int32OperandId());
-
-  Maybe<Register> valInt32;
-  Maybe<ConstantOrRegister> valFloat;
-  switch (arrayType) {
-    case Scalar::Int8:
-    case Scalar::Uint8:
-    case Scalar::Int16:
-    case Scalar::Uint16:
-    case Scalar::Int32:
-    case Scalar::Uint32:
-    case Scalar::Uint8Clamped:
-      valInt32.emplace(allocator.useRegister(masm, reader.int32OperandId()));
-      break;
-
-    case Scalar::Float32:
-    case Scalar::Float64:
-      valFloat.emplace(
-          allocator.useConstantOrRegister(masm, reader.numberOperandId()));
-      break;
-
-    case Scalar::BigInt64:
-    case Scalar::BigUint64:
-    case Scalar::MaxTypedArrayViewType:
-    case Scalar::Int64:
-      MOZ_CRASH("Unsupported TypedArray type");
-  }
-
-  bool handleOOB = reader.readBool();
-
-  AutoScratchRegister scratch1(allocator, masm);
-  AutoScratchRegister scratch2(allocator, masm);
-
-  FailurePath* failure;
-  if (!addFailurePath(&failure)) {
-    return false;
-  }
-
-  // Bounds check.
-  Label done;
-  LoadTypedThingLength(masm, layout, obj, scratch1);
-  masm.spectreBoundsCheck32(index, scratch1, scratch2,
-                            handleOOB ? &done : failure->label());
-
-  // Load the elements vector.
-  LoadTypedThingData(masm, layout, obj, scratch1);
-
-  BaseIndex dest(scratch1, index,
-                 ScaleFromElemWidth(Scalar::byteSize(arrayType)));
-
-  FloatRegister maybeTempDouble = ic_->asSetPropertyIC()->maybeTempDouble();
-  FloatRegister maybeTempFloat32 = ic_->asSetPropertyIC()->maybeTempFloat32();
-  MOZ_ASSERT(maybeTempDouble != InvalidFloatReg);
-  MOZ_ASSERT_IF(jit::hasUnaliasedDouble(), maybeTempFloat32 != InvalidFloatReg);
-
-  if (arrayType == Scalar::Float32) {
-    FloatRegister tempFloat =
-        hasUnaliasedDouble() ? maybeTempFloat32 : maybeTempDouble;
-    if (!masm.convertConstantOrRegisterToFloat(cx_, *valFloat, tempFloat,
-                                               failure->label())) {
-      return false;
-    }
-    masm.storeToTypedFloatArray(arrayType, tempFloat, dest);
-  } else if (arrayType == Scalar::Float64) {
-    if (!masm.convertConstantOrRegisterToDouble(cx_, *valFloat, maybeTempDouble,
-                                                failure->label())) {
-      return false;
-    }
-    masm.storeToTypedFloatArray(arrayType, maybeTempDouble, dest);
-  } else {
-    masm.storeToTypedIntArray(arrayType, *valInt32, dest);
-  }
-
-  masm.bind(&done);
-  return true;
-}
-
 bool IonCacheIRCompiler::emitCallNativeSetter() {
   JitSpew(JitSpew_Codegen, __FUNCTION__);
   AutoSaveLiveRegisters save(*this);
 
   Register obj = allocator.useRegister(masm, reader.objOperandId());
   JSFunction* target = &objectStubField(reader.stubOffset())->as<JSFunction>();
   MOZ_ASSERT(target->isNative());
   ConstantOrRegister val =
--- a/js/src/jit/IonIC.h
+++ b/js/src/jit/IonIC.h
@@ -280,53 +280,46 @@ class IonGetPropSuperIC : public IonIC {
                                   MutableHandleValue res);
 };
 
 class IonSetPropertyIC : public IonIC {
   LiveRegisterSet liveRegs_;
 
   Register object_;
   Register temp_;
-  FloatRegister maybeTempDouble_;
-  FloatRegister maybeTempFloat32_;
   ConstantOrRegister id_;
   ConstantOrRegister rhs_;
   bool strict_ : 1;
   bool needsPostBarrier_ : 1;
   bool needsTypeBarrier_ : 1;
   bool guardHoles_ : 1;
 
  public:
   IonSetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, Register object,
-                   Register temp, FloatRegister maybeTempDouble,
-                   FloatRegister maybeTempFloat32, const ConstantOrRegister& id,
+                   Register temp, const ConstantOrRegister& id,
                    const ConstantOrRegister& rhs, bool strict,
                    bool needsPostBarrier, bool needsTypeBarrier,
                    bool guardHoles)
       : IonIC(kind),
         liveRegs_(liveRegs),
         object_(object),
         temp_(temp),
-        maybeTempDouble_(maybeTempDouble),
-        maybeTempFloat32_(maybeTempFloat32),
         id_(id),
         rhs_(rhs),
         strict_(strict),
         needsPostBarrier_(needsPostBarrier),
         needsTypeBarrier_(needsTypeBarrier),
         guardHoles_(guardHoles) {}
 
   LiveRegisterSet liveRegs() const { return liveRegs_; }
   Register object() const { return object_; }
   ConstantOrRegister id() const { return id_; }
   ConstantOrRegister rhs() const { return rhs_; }
 
   Register temp() const { return temp_; }
-  FloatRegister maybeTempDouble() const { return maybeTempDouble_; }
-  FloatRegister maybeTempFloat32() const { return maybeTempFloat32_; }
 
   bool strict() const { return strict_; }
   bool needsPostBarrier() const { return needsPostBarrier_; }
   bool needsTypeBarrier() const { return needsTypeBarrier_; }
   bool guardHoles() const { return guardHoles_; }
 
   static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript,
                                   IonSetPropertyIC* ic, HandleObject obj,
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3898,29 +3898,26 @@ void LIRGenerator::visitSetPropertyCache
   bool useConstId =
       id->type() == MIRType::String || id->type() == MIRType::Symbol;
   bool useConstValue = IsNonNurseryConstant(ins->value());
 
   // Emit an overrecursed check: this is necessary because the cache can
   // attach a scripted setter stub that calls this script recursively.
   gen->setNeedsOverrecursedCheck();
 
-  // We need a double/float32 temp register for typed array stubs if this is
-  // a SETELEM or INITELEM op.
+  // We need a double temp register for typed array stubs if this is a SETELEM
+  // or INITELEM op.
   LDefinition tempD = LDefinition::BogusTemp();
-  LDefinition tempF32 = LDefinition::BogusTemp();
   if (IsElemPC(ins->resumePoint()->pc())) {
-    tempD = tempDouble();
-    tempF32 = hasUnaliasedDouble() ? tempFloat32() : LDefinition::BogusTemp();
+    tempD = tempFixed(FloatReg0);
   }
 
   LInstruction* lir = new (alloc()) LSetPropertyCache(
       useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId),
-      useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD,
-      tempF32);
+      useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD);
   add(lir, ins);
   assignSafepoint(lir, ins);
 }
 
 void LIRGenerator::visitCallSetElement(MCallSetElement* ins) {
   MOZ_ASSERT(ins->object()->type() == MIRType::Object);
   MOZ_ASSERT(ins->index()->type() == MIRType::Value);
   MOZ_ASSERT(ins->value()->type() == MIRType::Value);
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -5410,46 +5410,39 @@ class LCallDeleteElement : public LCallI
     setBoxOperand(Value, value);
     setBoxOperand(Index, index);
   }
 
   MDeleteElement* mir() const { return mir_->toDeleteElement(); }
 };
 
 // Patchable jump to stubs generated for a SetProperty cache.
-class LSetPropertyCache : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 3> {
+class LSetPropertyCache : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 2> {
  public:
   LIR_HEADER(SetPropertyCache)
 
+  // Takes an additional temp: this is intendend to be FloatReg0 to allow the
+  // actual cache code to safely clobber that value without save and restore.
   LSetPropertyCache(const LAllocation& object, const LBoxAllocation& id,
                     const LBoxAllocation& value, const LDefinition& temp,
-                    const LDefinition& tempDouble,
-                    const LDefinition& tempFloat32)
+                    const LDefinition& tempDouble)
       : LInstructionHelper(classOpcode) {
     setOperand(0, object);
     setBoxOperand(Id, id);
     setBoxOperand(Value, value);
     setTemp(0, temp);
     setTemp(1, tempDouble);
-    setTemp(2, tempFloat32);
   }
 
   static const size_t Id = 1;
   static const size_t Value = 1 + BOX_PIECES;
 
   const MSetPropertyCache* mir() const { return mir_->toSetPropertyCache(); }
 
   const LDefinition* temp() { return getTemp(0); }
-  const LDefinition* tempDouble() { return getTemp(1); }
-  const LDefinition* tempFloat32() {
-    if (hasUnaliasedDouble()) {
-      return getTemp(2);
-    }
-    return getTemp(1);
-  }
 };
 
 class LGetIteratorCache : public LInstructionHelper<1, BOX_PIECES, 2> {
  public:
   LIR_HEADER(GetIteratorCache)
 
   static const size_t Value = 0;