Bug 1523941 - Always use ScratchDoubleScope / ScratchFloat32Scope. r=nbp
authorLars T Hansen <lhansen@mozilla.com>
Thu, 31 Jan 2019 07:51:14 +0100
changeset 456370 e565291ee5f6c863a5e247c078f0358142fb0062
parent 456369 648e0d2c5ef838186b7a4f688cf5568fea4829bb
child 456371 a5f0e7af6f5c9b45e6360ae86005ee75b2a1bb63
push idunknown
push userunknown
push dateunknown
reviewersnbp
bugs1523941
milestone67.0a1
Bug 1523941 - Always use ScratchDoubleScope / ScratchFloat32Scope. r=nbp Remove all(*) uses of ScratchDoubleReg / ScratchFloat32Reg in common code and tier-1 macro-assemblers, and use ScratchDoubleScope / ScratchFloat32Scope exclusively. This sometimes leads to a very minor amount of extra code, but ensures that we do not reuse a live register. (*) There are a couple of uses left, but these only check that the scratch regs aren't used where they can't be used or check whether the scratch regs need to be saved and restored across a call to external code.
js/src/jit/BaselineIC.cpp
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/IonCacheIRCompiler.cpp
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm64/CodeGenerator-arm64.cpp
js/src/jit/arm64/MacroAssembler-arm64.cpp
js/src/jit/none/MacroAssembler-none.h
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
js/src/jit/x86/CodeGenerator-x86.cpp
js/src/jit/x86/MacroAssembler-x86-inl.h
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/jit/x86/MacroAssembler-x86.h
js/src/wasm/WasmStubs.cpp
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -2438,18 +2438,19 @@ template <typename T>
 void StoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type,
                        const ValueOperand& value, const T& dest,
                        Register scratch, Label* failure) {
   Label done;
 
   if (type == Scalar::Float32 || type == Scalar::Float64) {
     masm.ensureDouble(value, FloatReg0, failure);
     if (type == Scalar::Float32) {
-      masm.convertDoubleToFloat32(FloatReg0, ScratchFloat32Reg);
-      masm.storeToTypedFloatArray(type, ScratchFloat32Reg, dest);
+      ScratchFloat32Scope fpscratch(masm);
+      masm.convertDoubleToFloat32(FloatReg0, fpscratch);
+      masm.storeToTypedFloatArray(type, fpscratch, dest);
     } else {
       masm.storeToTypedFloatArray(type, FloatReg0, dest);
     }
   } else if (type == Scalar::Uint8Clamped) {
     Label notInt32;
     masm.branchTestInt32(Assembler::NotEqual, value, &notInt32);
     masm.unboxInt32(value, scratch);
     masm.clampIntToUint8(scratch);
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -75,17 +75,20 @@ ValueOperand CacheRegisterAllocator::use
       popPayload(masm, &loc, reg.scratchReg());
       masm.tagValue(loc.payloadType(), reg.scratchReg(), reg);
       loc.setValueReg(reg);
       return reg;
     }
 
     case OperandLocation::DoubleReg: {
       ValueOperand reg = allocateValueRegister(masm);
-      masm.boxDouble(loc.doubleReg(), reg, ScratchDoubleReg);
+      {
+        ScratchDoubleScope fpscratch(masm);
+        masm.boxDouble(loc.doubleReg(), reg, fpscratch);
+      }
       loc.setValueReg(reg);
       return reg;
     }
 
     case OperandLocation::Uninitialized:
       break;
   }
 
@@ -166,19 +169,21 @@ ValueOperand CacheRegisterAllocator::use
       MOZ_ASSERT(!currentOpRegs_.has(loc.payloadReg()),
                  "Register shouldn't be in use");
       availableRegs_.add(loc.payloadReg());
       break;
     case OperandLocation::PayloadStack:
       popPayload(masm, &loc, reg.scratchReg());
       masm.tagValue(loc.payloadType(), reg.scratchReg(), reg);
       break;
-    case OperandLocation::DoubleReg:
-      masm.boxDouble(loc.doubleReg(), reg, ScratchDoubleReg);
+    case OperandLocation::DoubleReg: {
+      ScratchDoubleScope fpscratch(masm);
+      masm.boxDouble(loc.doubleReg(), reg, fpscratch);
       break;
+    }
     case OperandLocation::Uninitialized:
       MOZ_CRASH();
   }
 
   loc.setValueReg(reg);
   return reg;
 }
 
@@ -2392,18 +2397,19 @@ bool CacheIRCompiler::emitInt32URightShi
   masm.flexibleRshift32(rhs, lhs);
   Label intDone, floatDone;
   if (allowDouble) {
     Label toUint;
     masm.branchTest32(Assembler::Signed, lhs, lhs, &toUint);
     masm.jump(&intDone);
 
     masm.bind(&toUint);
-    masm.convertUInt32ToDouble(lhs, ScratchDoubleReg);
-    masm.boxDouble(ScratchDoubleReg, output.valueReg(), ScratchDoubleReg);
+    ScratchDoubleScope fpscratch(masm);
+    masm.convertUInt32ToDouble(lhs, fpscratch);
+    masm.boxDouble(fpscratch, output.valueReg(), fpscratch);
     masm.jump(&floatDone);
   } else {
     masm.branchTest32(Assembler::Signed, lhs, lhs, failure->label());
   }
   masm.bind(&intDone);
   EmitStoreResult(masm, lhs, JSVAL_TYPE_INT32, output);
   masm.bind(&floatDone);
   return true;
@@ -2518,21 +2524,24 @@ bool CacheIRCompiler::emitDoubleIncDecRe
   Label failurePopReg, done;
   if (mode_ != Mode::Baseline) {
     masm.push(FloatReg0);
   }
 
   masm.ensureDouble(
       val, FloatReg0,
       (mode_ != Mode::Baseline) ? &failurePopReg : failure->label());
-  masm.loadConstantDouble(1.0, ScratchDoubleReg);
-  if (isInc) {
-    masm.addDouble(ScratchDoubleReg, FloatReg0);
-  } else {
-    masm.subDouble(ScratchDoubleReg, FloatReg0);
+  {
+    ScratchDoubleScope fpscratch(masm);
+    masm.loadConstantDouble(1.0, fpscratch);
+    if (isInc) {
+      masm.addDouble(fpscratch, FloatReg0);
+    } else {
+      masm.subDouble(fpscratch, FloatReg0);
+    }
   }
   masm.boxDouble(FloatReg0, output.valueReg(), FloatReg0);
 
   if (mode_ != Mode::Baseline) {
     masm.pop(FloatReg0);
     masm.jump(&done);
 
     masm.bind(&failurePopReg);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -607,18 +607,19 @@ void CodeGenerator::visitValueToFloat32(
   masm.bind(&isInt32);
   masm.int32ValueToFloat32(operand, output);
   masm.jump(&done);
 
   masm.bind(&isDouble);
   // ARM and MIPS may not have a double register available if we've
   // allocated output as a float32.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
-  masm.unboxDouble(operand, ScratchDoubleReg);
-  masm.convertDoubleToFloat32(ScratchDoubleReg, output);
+  ScratchDoubleScope fpscratch(masm);
+  masm.unboxDouble(operand, fpscratch);
+  masm.convertDoubleToFloat32(fpscratch, output);
 #else
   masm.unboxDouble(operand, output);
   masm.convertDoubleToFloat32(output, output);
 #endif
   masm.bind(&done);
 }
 
 void CodeGenerator::visitInt32ToDouble(LInt32ToDouble* lir) {
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -1793,24 +1793,25 @@ static void EmitStoreDenseElement(MacroA
   Label convert, storeValue, done;
   masm.branchTest32(Assembler::NonZero, elementsFlags,
                     Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS), &convert);
   masm.bind(&storeValue);
   masm.storeTypedOrValue(reg, target);
   masm.jump(&done);
 
   masm.bind(&convert);
+  ScratchDoubleScope fpscratch(masm);
   if (reg.hasValue()) {
     masm.branchTestInt32(Assembler::NotEqual, reg.valueReg(), &storeValue);
-    masm.int32ValueToDouble(reg.valueReg(), ScratchDoubleReg);
-    masm.storeDouble(ScratchDoubleReg, target);
+    masm.int32ValueToDouble(reg.valueReg(), fpscratch);
+    masm.storeDouble(fpscratch, target);
   } else {
     MOZ_ASSERT(reg.type() == MIRType::Int32);
-    masm.convertInt32ToDouble(reg.typedReg().gpr(), ScratchDoubleReg);
-    masm.storeDouble(ScratchDoubleReg, target);
+    masm.convertInt32ToDouble(reg.typedReg().gpr(), fpscratch);
+    masm.storeDouble(fpscratch, target);
   }
 
   masm.bind(&done);
 }
 
 static void EmitAssertNoCopyOnWriteElements(MacroAssembler& masm,
                                             Register elementsReg) {
 #ifdef DEBUG
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -463,37 +463,43 @@ void MacroAssembler::loadFromTypedArray(
         Label done, isDouble;
         branchTest32(Assembler::Signed, temp, temp, &isDouble);
         {
           tagValue(JSVAL_TYPE_INT32, temp, dest);
           jump(&done);
         }
         bind(&isDouble);
         {
-          convertUInt32ToDouble(temp, ScratchDoubleReg);
-          boxDouble(ScratchDoubleReg, dest, ScratchDoubleReg);
+          ScratchDoubleScope fpscratch(*this);
+          convertUInt32ToDouble(temp, fpscratch);
+          boxDouble(fpscratch, dest, fpscratch);
         }
         bind(&done);
       } else {
         // Bailout if the value does not fit in an int32.
         branchTest32(Assembler::Signed, temp, temp, fail);
         tagValue(JSVAL_TYPE_INT32, temp, dest);
       }
       break;
-    case Scalar::Float32:
-      loadFromTypedArray(arrayType, src, AnyRegister(ScratchFloat32Reg),
+    case Scalar::Float32: {
+      ScratchDoubleScope dscratch(*this);
+      FloatRegister fscratch = dscratch.asSingle();
+      loadFromTypedArray(arrayType, src, AnyRegister(fscratch),
                          dest.scratchReg(), nullptr);
-      convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
-      boxDouble(ScratchDoubleReg, dest, ScratchDoubleReg);
+      convertFloat32ToDouble(fscratch, dscratch);
+      boxDouble(dscratch, dest, dscratch);
       break;
-    case Scalar::Float64:
-      loadFromTypedArray(arrayType, src, AnyRegister(ScratchDoubleReg),
+    }
+    case Scalar::Float64: {
+      ScratchDoubleScope fpscratch(*this);
+      loadFromTypedArray(arrayType, src, AnyRegister(fpscratch),
                          dest.scratchReg(), nullptr);
-      boxDouble(ScratchDoubleReg, dest, ScratchDoubleReg);
+      boxDouble(fpscratch, dest, fpscratch);
       break;
+    }
     default:
       MOZ_CRASH("Invalid typed array type");
   }
 }
 
 template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType,
                                                  const Address& src,
                                                  const ValueOperand& dest,
@@ -662,36 +668,41 @@ void MacroAssembler::storeUnboxedPropert
         storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4,
                             type);
       }
       break;
 
     case JSVAL_TYPE_DOUBLE:
       if (value.constant()) {
         if (value.value().isNumber()) {
-          loadConstantDouble(value.value().toNumber(), ScratchDoubleReg);
-          storeDouble(ScratchDoubleReg, address);
+          ScratchDoubleScope fpscratch(*this);
+          loadConstantDouble(value.value().toNumber(), fpscratch);
+          storeDouble(fpscratch, address);
         } else {
           StoreUnboxedFailure(*this, failure);
         }
       } else if (value.reg().hasTyped()) {
         if (value.reg().type() == MIRType::Int32) {
-          convertInt32ToDouble(value.reg().typedReg().gpr(), ScratchDoubleReg);
-          storeDouble(ScratchDoubleReg, address);
+          ScratchDoubleScope fpscratch(*this);
+          convertInt32ToDouble(value.reg().typedReg().gpr(), fpscratch);
+          storeDouble(fpscratch, address);
         } else if (value.reg().type() == MIRType::Double) {
           storeDouble(value.reg().typedReg().fpu(), address);
         } else {
           StoreUnboxedFailure(*this, failure);
         }
       } else {
         ValueOperand reg = value.reg().valueReg();
         Label notInt32, end;
         branchTestInt32(Assembler::NotEqual, reg, &notInt32);
-        int32ValueToDouble(reg, ScratchDoubleReg);
-        storeDouble(ScratchDoubleReg, address);
+        {
+          ScratchDoubleScope fpscratch(*this);
+          int32ValueToDouble(reg, fpscratch);
+          storeDouble(fpscratch, address);
+        }
         jump(&end);
         bind(&notInt32);
         if (failure) {
           branchTestDouble(Assembler::NotEqual, reg, failure);
         }
         storeValue(reg, address);
         bind(&end);
       }
@@ -2226,26 +2237,28 @@ void MacroAssembler::tracelogStopId(Regi
   PopRegsInMask(save);
 }
 #endif
 
 void MacroAssembler::convertInt32ValueToDouble(const Address& address,
                                                Register scratch, Label* done) {
   branchTestInt32(Assembler::NotEqual, address, done);
   unboxInt32(address, scratch);
-  convertInt32ToDouble(scratch, ScratchDoubleReg);
-  storeDouble(ScratchDoubleReg, address);
+  ScratchDoubleScope fpscratch(*this);
+  convertInt32ToDouble(scratch, fpscratch);
+  storeDouble(fpscratch, address);
 }
 
 void MacroAssembler::convertInt32ValueToDouble(ValueOperand val) {
   Label done;
   branchTestInt32(Assembler::NotEqual, val, &done);
   unboxInt32(val, val.scratchReg());
-  convertInt32ToDouble(val.scratchReg(), ScratchDoubleReg);
-  boxDouble(ScratchDoubleReg, val, ScratchDoubleReg);
+  ScratchDoubleScope fpscratch(*this);
+  convertInt32ToDouble(val.scratchReg(), fpscratch);
+  boxDouble(fpscratch, val, fpscratch);
   bind(&done);
 }
 
 void MacroAssembler::convertValueToFloatingPoint(ValueOperand value,
                                                  FloatRegister output,
                                                  Label* fail,
                                                  MIRType outputType) {
   Label isDouble, isInt32, isBool, isNull, done;
@@ -2273,25 +2286,29 @@ void MacroAssembler::convertValueToFloat
   bind(&isBool);
   boolValueToFloatingPoint(value, output, outputType);
   jump(&done);
 
   bind(&isInt32);
   int32ValueToFloatingPoint(value, output, outputType);
   jump(&done);
 
+  // On some non-multiAlias platforms, unboxDouble may use the scratch register,
+  // so do not merge code paths here.
   bind(&isDouble);
-  FloatRegister tmp = output.asDouble();
   if (outputType == MIRType::Float32 && hasMultiAlias()) {
-    tmp = ScratchDoubleReg;
-  }
-
-  unboxDouble(value, tmp);
-  if (outputType == MIRType::Float32) {
+    ScratchDoubleScope tmp(*this);
+    unboxDouble(value, tmp);
     convertDoubleToFloat32(tmp, output);
+  } else {
+    FloatRegister tmp = output.asDouble();
+    unboxDouble(value, tmp);
+    if (outputType == MIRType::Float32) {
+      convertDoubleToFloat32(tmp, output);
+    }
   }
 
   bind(&done);
 }
 
 bool MacroAssembler::convertValueToFloatingPoint(JSContext* cx, const Value& v,
                                                  FloatRegister output,
                                                  Label* fail,
@@ -2397,19 +2414,20 @@ void MacroAssembler::convertTypedOrValue
 }
 
 void MacroAssembler::outOfLineTruncateSlow(FloatRegister src, Register dest,
                                            bool widenFloatToDouble,
                                            bool compilingWasm,
                                            wasm::BytecodeOffset callOffset) {
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
     defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+  ScratchDoubleScope fpscratch(*this);
   if (widenFloatToDouble) {
-    convertFloat32ToDouble(src, ScratchDoubleReg);
-    src = ScratchDoubleReg;
+    convertFloat32ToDouble(src, fpscratch);
+    src = fpscratch;
   }
 #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   FloatRegister srcSingle;
   if (widenFloatToDouble) {
     MOZ_ASSERT(src.isSingle());
     srcSingle = src;
     src = src.asDouble();
     Push(srcSingle);
@@ -2934,20 +2952,22 @@ void MacroAssembler::Push(jsid id, Regis
 }
 
 void MacroAssembler::Push(TypedOrValueRegister v) {
   if (v.hasValue()) {
     Push(v.valueReg());
   } else if (IsFloatingPointType(v.type())) {
     FloatRegister reg = v.typedReg().fpu();
     if (v.type() == MIRType::Float32) {
-      convertFloat32ToDouble(reg, ScratchDoubleReg);
-      reg = ScratchDoubleReg;
+      ScratchDoubleScope fpscratch(*this);
+      convertFloat32ToDouble(reg, fpscratch);
+      Push(fpscratch);
+    } else {
+      Push(reg);
     }
-    Push(reg);
   } else {
     Push(ValueTypeFromMIRType(v.type()), v.typedReg().gpr());
   }
 }
 
 void MacroAssembler::Push(const ConstantOrRegister& v) {
   if (v.constant()) {
     Push(v.value());
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -2543,20 +2543,22 @@ class MacroAssembler : public MacroAssem
 
   template <typename T>
   void storeTypedOrValue(TypedOrValueRegister src, const T& dest) {
     if (src.hasValue()) {
       storeValue(src.valueReg(), dest);
     } else if (IsFloatingPointType(src.type())) {
       FloatRegister reg = src.typedReg().fpu();
       if (src.type() == MIRType::Float32) {
-        convertFloat32ToDouble(reg, ScratchDoubleReg);
-        reg = ScratchDoubleReg;
+        ScratchDoubleScope fpscratch(*this);
+        convertFloat32ToDouble(reg, fpscratch);
+        storeDouble(fpscratch, dest);
+      } else {
+        storeDouble(reg, dest);
       }
-      storeDouble(reg, dest);
     } else {
       storeValue(ValueTypeFromMIRType(src.type()), src.typedReg().gpr(), dest);
     }
   }
 
   template <typename T>
   inline void storeObjectOrNull(Register src, const T& dest);
 
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -2438,19 +2438,19 @@ void CodeGenerator::visitWasmTruncateToI
 
   OutOfLineWasmTruncateCheck* ool = nullptr;
   if (!lir->mir()->isSaturating()) {
     ool = new (alloc())
         OutOfLineWasmTruncateCheck(mir, input, Register64::Invalid());
     addOutOfLineCode(ool, mir);
   }
 
-  ScratchDoubleScope scratchScope(masm);
+  ScratchDoubleScope fpscratch(masm);
   if (fromType == MIRType::Float32) {
-    inputDouble = ScratchDoubleReg;
+    inputDouble = fpscratch;
     masm.convertFloat32ToDouble(input, inputDouble);
   }
 
   masm.Push(input);
 
   masm.setupWasmABICall();
   masm.passABIArg(inputDouble, MoveOp::DOUBLE);
 
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4469,21 +4469,21 @@ void MacroAssembler::moveValue(const Typ
   if (!IsFloatingPointType(type)) {
     mov(ImmWord(MIRTypeToTag(type)), dest.typeReg());
     if (reg.gpr() != dest.payloadReg()) {
       mov(reg.gpr(), dest.payloadReg());
     }
     return;
   }
 
-  ScratchDoubleScope scratch(*this);
+  ScratchFloat32Scope scratch(*this);
   FloatRegister freg = reg.fpu();
   if (type == MIRType::Float32) {
-    convertFloat32ToDouble(freg, ScratchFloat32Reg);
-    freg = ScratchFloat32Reg;
+    convertFloat32ToDouble(freg, scratch);
+    freg = scratch;
   }
   ma_vxfer(freg, dest.payloadReg(), dest.typeReg());
 }
 
 void MacroAssembler::moveValue(const ValueOperand& src,
                                const ValueOperand& dest) {
   Register s0 = src.typeReg();
   Register s1 = src.payloadReg();
--- a/js/src/jit/arm64/CodeGenerator-arm64.cpp
+++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp
@@ -944,18 +944,18 @@ void CodeGenerator::visitCeilF(LCeilF* l
   masm.ceilf(input, output, &bailout);
   bailoutFrom(&bailout, lir->snapshot());
 }
 
 void CodeGenerator::visitRound(LRound* lir) {
   const FloatRegister input = ToFloatRegister(lir->input());
   const ARMFPRegister input64(input, 64);
   const FloatRegister temp = ToFloatRegister(lir->temp());
-  const FloatRegister scratch = ScratchDoubleReg;
   const Register output = ToRegister(lir->output());
+  ScratchDoubleScope scratch(masm);
 
   Label negative, done;
 
   // Branch to a slow path if input < 0.0 due to complicated rounding rules.
   // Note that Fcmp with NaN unsets the negative flag.
   masm.Fcmp(input64, 0.0);
   masm.B(&negative, Assembler::Condition::lo);
 
@@ -1021,18 +1021,18 @@ void CodeGenerator::visitRound(LRound* l
 
   masm.bind(&done);
 }
 
 void CodeGenerator::visitRoundF(LRoundF* lir) {
   const FloatRegister input = ToFloatRegister(lir->input());
   const ARMFPRegister input32(input, 32);
   const FloatRegister temp = ToFloatRegister(lir->temp());
-  const FloatRegister scratch = ScratchFloat32Reg;
   const Register output = ToRegister(lir->output());
+  ScratchFloat32Scope scratch(masm);
 
   Label negative, done;
 
   // Branch to a slow path if input < 0.0 due to complicated rounding rules.
   // Note that Fcmp with NaN unsets the negative flag.
   masm.Fcmp(input32, 0.0);
   masm.B(&negative, Assembler::Condition::lo);
 
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -894,17 +894,17 @@ void MacroAssembler::moveValue(const Typ
   MIRType type = src.type();
   AnyRegister reg = src.typedReg();
 
   if (!IsFloatingPointType(type)) {
     boxNonDouble(ValueTypeFromMIRType(type), reg.gpr(), dest);
     return;
   }
 
-  FloatRegister scratch = ScratchDoubleReg;
+  ScratchDoubleScope scratch(*this);
   FloatRegister freg = reg.fpu();
   if (type == MIRType::Float32) {
     convertFloat32ToDouble(freg, scratch);
     freg = scratch;
   }
   boxDouble(freg, dest, scratch);
 }
 
@@ -1230,28 +1230,29 @@ void MacroAssembler::oolWasmTruncateChec
                                                   Label* rejoin) {
   Label notNaN;
   branchFloat(Assembler::DoubleOrdered, input, input, &notNaN);
   wasmTrap(wasm::Trap::InvalidConversionToInteger, off);
   bind(&notNaN);
 
   Label isOverflow;
   const float two_31 = -float(INT32_MIN);
+  ScratchFloat32Scope fpscratch(*this);
   if (flags & TRUNC_UNSIGNED) {
-    loadConstantFloat32(two_31 * 2, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchFloat32Reg,
+    loadConstantFloat32(two_31 * 2, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                 &isOverflow);
-    loadConstantFloat32(-1.0f, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThan, input, ScratchFloat32Reg, rejoin);
+    loadConstantFloat32(-1.0f, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThan, input, fpscratch, rejoin);
   } else {
-    loadConstantFloat32(two_31, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchFloat32Reg,
+    loadConstantFloat32(two_31, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                 &isOverflow);
-    loadConstantFloat32(-two_31, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchFloat32Reg,
+    loadConstantFloat32(-two_31, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                 rejoin);
   }
   bind(&isOverflow);
   wasmTrap(wasm::Trap::IntegerOverflow, off);
 }
 
 void MacroAssembler::oolWasmTruncateCheckF64ToI32(FloatRegister input,
                                                   Register output,
@@ -1260,28 +1261,29 @@ void MacroAssembler::oolWasmTruncateChec
                                                   Label* rejoin) {
   Label notNaN;
   branchDouble(Assembler::DoubleOrdered, input, input, &notNaN);
   wasmTrap(wasm::Trap::InvalidConversionToInteger, off);
   bind(&notNaN);
 
   Label isOverflow;
   const double two_31 = -double(INT32_MIN);
+  ScratchDoubleScope fpscratch(*this);
   if (flags & TRUNC_UNSIGNED) {
-    loadConstantDouble(two_31 * 2, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg,
+    loadConstantDouble(two_31 * 2, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                  &isOverflow);
-    loadConstantDouble(-1.0, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg, rejoin);
+    loadConstantDouble(-1.0, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThan, input, fpscratch, rejoin);
   } else {
-    loadConstantDouble(two_31, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg,
+    loadConstantDouble(two_31, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                  &isOverflow);
-    loadConstantDouble(-two_31 - 1, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg, rejoin);
+    loadConstantDouble(-two_31 - 1, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThan, input, fpscratch, rejoin);
   }
   bind(&isOverflow);
   wasmTrap(wasm::Trap::IntegerOverflow, off);
 }
 
 void MacroAssembler::oolWasmTruncateCheckF32ToI64(FloatRegister input,
                                                   Register64 output,
                                                   TruncFlags flags,
@@ -1289,28 +1291,29 @@ void MacroAssembler::oolWasmTruncateChec
                                                   Label* rejoin) {
   Label notNaN;
   branchFloat(Assembler::DoubleOrdered, input, input, &notNaN);
   wasmTrap(wasm::Trap::InvalidConversionToInteger, off);
   bind(&notNaN);
 
   Label isOverflow;
   const float two_63 = -float(INT64_MIN);
+  ScratchFloat32Scope fpscratch(*this);
   if (flags & TRUNC_UNSIGNED) {
-    loadConstantFloat32(two_63 * 2, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchFloat32Reg,
+    loadConstantFloat32(two_63 * 2, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                 &isOverflow);
-    loadConstantFloat32(-1.0f, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThan, input, ScratchFloat32Reg, rejoin);
+    loadConstantFloat32(-1.0f, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThan, input, fpscratch, rejoin);
   } else {
-    loadConstantFloat32(two_63, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchFloat32Reg,
+    loadConstantFloat32(two_63, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                 &isOverflow);
-    loadConstantFloat32(-two_63, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchFloat32Reg,
+    loadConstantFloat32(-two_63, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                 rejoin);
   }
   bind(&isOverflow);
   wasmTrap(wasm::Trap::IntegerOverflow, off);
 }
 
 void MacroAssembler::oolWasmTruncateCheckF64ToI64(FloatRegister input,
                                                   Register64 output,
@@ -1319,28 +1322,29 @@ void MacroAssembler::oolWasmTruncateChec
                                                   Label* rejoin) {
   Label notNaN;
   branchDouble(Assembler::DoubleOrdered, input, input, &notNaN);
   wasmTrap(wasm::Trap::InvalidConversionToInteger, off);
   bind(&notNaN);
 
   Label isOverflow;
   const double two_63 = -double(INT64_MIN);
+  ScratchDoubleScope fpscratch(*this);
   if (flags & TRUNC_UNSIGNED) {
-    loadConstantDouble(two_63 * 2, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg,
+    loadConstantDouble(two_63 * 2, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                  &isOverflow);
-    loadConstantDouble(-1.0, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg, rejoin);
+    loadConstantDouble(-1.0, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThan, input, fpscratch, rejoin);
   } else {
-    loadConstantDouble(two_63, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg,
+    loadConstantDouble(two_63, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                  &isOverflow);
-    loadConstantDouble(-two_63, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg,
+    loadConstantDouble(-two_63, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                  rejoin);
   }
   bind(&isOverflow);
   wasmTrap(wasm::Trap::IntegerOverflow, off);
 }
 
 void MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access,
                               Register memoryBase, Register ptr,
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -22,16 +22,24 @@ static constexpr FloatRegister ReturnDou
 static constexpr FloatRegister ReturnSimd128Reg = {FloatRegisters::invalid_reg};
 static constexpr FloatRegister ScratchFloat32Reg = {
     FloatRegisters::invalid_reg};
 static constexpr FloatRegister ScratchDoubleReg = {FloatRegisters::invalid_reg};
 static constexpr FloatRegister ScratchSimd128Reg = {
     FloatRegisters::invalid_reg};
 static constexpr FloatRegister InvalidFloatReg = {FloatRegisters::invalid_reg};
 
+struct ScratchFloat32Scope : FloatRegister {
+  explicit ScratchFloat32Scope(MacroAssembler& masm) {}
+};
+
+struct ScratchDoubleScope : FloatRegister {
+  explicit ScratchDoubleScope(MacroAssembler& masm) {}
+};
+
 static constexpr Register OsrFrameReg{Registers::invalid_reg};
 static constexpr Register PreBarrierReg{Registers::invalid_reg};
 static constexpr Register CallTempReg0{Registers::invalid_reg};
 static constexpr Register CallTempReg1{Registers::invalid_reg};
 static constexpr Register CallTempReg2{Registers::invalid_reg};
 static constexpr Register CallTempReg3{Registers::invalid_reg};
 static constexpr Register CallTempReg4{Registers::invalid_reg};
 static constexpr Register CallTempReg5{Registers::invalid_reg};
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -1223,23 +1223,22 @@ class VerifyOp {
  public:
   VerifyOp(MacroAssembler& masm, Label* failure)
       : masm(masm), failure_(failure) {}
 
   void operator()(Register reg, Address dump) {
     masm.branchPtr(Assembler::NotEqual, dump, reg, failure_);
   }
   void operator()(FloatRegister reg, Address dump) {
-    FloatRegister scratch;
     if (reg.isDouble()) {
-      scratch = ScratchDoubleReg;
+      ScratchDoubleScope scratch(masm);
       masm.loadDouble(dump, scratch);
       masm.branchDouble(Assembler::DoubleNotEqual, scratch, reg, failure_);
     } else if (reg.isSingle()) {
-      scratch = ScratchFloat32Reg;
+      ScratchFloat32Scope scratch(masm);
       masm.loadFloat32(dump, scratch);
       masm.branchFloat(Assembler::DoubleNotEqual, scratch, reg, failure_);
     }
 
     // :TODO: (Bug 1133745) Add support to verify SIMD registers.
   }
 };
 
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -736,35 +736,37 @@ void MacroAssembler::oolWasmTruncateChec
   bool isSaturating = flags & TRUNC_SATURATING;
 
   if (isSaturating) {
     if (isUnsigned) {
       // Negative overflow and NaN both are converted to 0, and the only
       // other case is positive overflow which is converted to
       // UINT32_MAX.
       Label nonNegative;
-      loadConstantDouble(0.0, ScratchDoubleReg);
-      branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg,
+      ScratchDoubleScope fpscratch(*this);
+      loadConstantDouble(0.0, fpscratch);
+      branchDouble(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                    &nonNegative);
       move32(Imm32(0), output);
       jump(rejoin);
 
       bind(&nonNegative);
       move32(Imm32(UINT32_MAX), output);
     } else {
       // Negative overflow is already saturated to INT32_MIN, so we only
       // have to handle NaN and positive overflow here.
       Label notNaN;
       branchDouble(Assembler::DoubleOrdered, input, input, &notNaN);
       move32(Imm32(0), output);
       jump(rejoin);
 
       bind(&notNaN);
-      loadConstantDouble(0.0, ScratchDoubleReg);
-      branchDouble(Assembler::DoubleLessThan, input, ScratchDoubleReg, rejoin);
+      ScratchDoubleScope fpscratch(*this);
+      loadConstantDouble(0.0, fpscratch);
+      branchDouble(Assembler::DoubleLessThan, input, fpscratch, rejoin);
       sub32(Imm32(1), output);
     }
     jump(rejoin);
     return;
   }
 
   AutoHandleWasmTruncateToIntErrors traps(*this, off);
 
@@ -775,22 +777,23 @@ void MacroAssembler::oolWasmTruncateChec
   if (isUnsigned) {
     return;
   }
 
   // Handle special values.
 
   // We've used vcvttsd2si. The only valid double values that can
   // truncate to INT32_MIN are in ]INT32_MIN - 1; INT32_MIN].
-  loadConstantDouble(double(INT32_MIN) - 1.0, ScratchDoubleReg);
-  branchDouble(Assembler::DoubleLessThanOrEqual, input, ScratchDoubleReg,
+  ScratchDoubleScope fpscratch(*this);
+  loadConstantDouble(double(INT32_MIN) - 1.0, fpscratch);
+  branchDouble(Assembler::DoubleLessThanOrEqual, input, fpscratch,
                &traps.intOverflow);
 
-  loadConstantDouble(0.0, ScratchDoubleReg);
-  branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg,
+  loadConstantDouble(0.0, fpscratch);
+  branchDouble(Assembler::DoubleGreaterThan, input, fpscratch,
                &traps.intOverflow);
   jump(rejoin);
 }
 
 void MacroAssembler::oolWasmTruncateCheckF32ToI32(FloatRegister input,
                                                   Register output,
                                                   TruncFlags flags,
                                                   wasm::BytecodeOffset off,
@@ -799,35 +802,37 @@ void MacroAssembler::oolWasmTruncateChec
   bool isSaturating = flags & TRUNC_SATURATING;
 
   if (isSaturating) {
     if (isUnsigned) {
       // Negative overflow and NaN both are converted to 0, and the only
       // other case is positive overflow which is converted to
       // UINT32_MAX.
       Label nonNegative;
-      loadConstantFloat32(0.0f, ScratchDoubleReg);
-      branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg,
+      ScratchFloat32Scope fpscratch(*this);
+      loadConstantFloat32(0.0f, fpscratch);
+      branchFloat(Assembler::DoubleGreaterThanOrEqual, input, fpscratch,
                   &nonNegative);
       move32(Imm32(0), output);
       jump(rejoin);
 
       bind(&nonNegative);
       move32(Imm32(UINT32_MAX), output);
     } else {
       // Negative overflow is already saturated to INT32_MIN, so we only
       // have to handle NaN and positive overflow here.
       Label notNaN;
       branchFloat(Assembler::DoubleOrdered, input, input, &notNaN);
       move32(Imm32(0), output);
       jump(rejoin);
 
       bind(&notNaN);
-      loadConstantFloat32(0.0f, ScratchFloat32Reg);
-      branchFloat(Assembler::DoubleLessThan, input, ScratchFloat32Reg, rejoin);
+      ScratchFloat32Scope fpscratch(*this);
+      loadConstantFloat32(0.0f, fpscratch);
+      branchFloat(Assembler::DoubleLessThan, input, fpscratch, rejoin);
       sub32(Imm32(1), output);
     }
     jump(rejoin);
     return;
   }
 
   AutoHandleWasmTruncateToIntErrors traps(*this, off);
 
@@ -839,19 +844,19 @@ void MacroAssembler::oolWasmTruncateChec
     return;
   }
 
   // Handle special values.
 
   // We've used vcvttss2si. Check that the input wasn't
   // float(INT32_MIN), which is the only legimitate input that
   // would truncate to INT32_MIN.
-  loadConstantFloat32(float(INT32_MIN), ScratchFloat32Reg);
-  branchFloat(Assembler::DoubleNotEqual, input, ScratchFloat32Reg,
-              &traps.intOverflow);
+  ScratchFloat32Scope fpscratch(*this);
+  loadConstantFloat32(float(INT32_MIN), fpscratch);
+  branchFloat(Assembler::DoubleNotEqual, input, fpscratch, &traps.intOverflow);
   jump(rejoin);
 }
 
 void MacroAssembler::oolWasmTruncateCheckF64ToI64(FloatRegister input,
                                                   Register64 output,
                                                   TruncFlags flags,
                                                   wasm::BytecodeOffset off,
                                                   Label* rejoin) {
@@ -859,63 +864,67 @@ void MacroAssembler::oolWasmTruncateChec
   bool isSaturating = flags & TRUNC_SATURATING;
 
   if (isSaturating) {
     if (isUnsigned) {
       // Negative overflow and NaN both are converted to 0, and the only
       // other case is positive overflow which is converted to
       // UINT64_MAX.
       Label positive;
-      loadConstantDouble(0.0, ScratchDoubleReg);
-      branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg,
+      ScratchDoubleScope fpscratch(*this);
+      loadConstantDouble(0.0, fpscratch);
+      branchDouble(Assembler::DoubleGreaterThan, input, fpscratch,
                    &positive);
       move64(Imm64(0), output);
       jump(rejoin);
 
       bind(&positive);
       move64(Imm64(UINT64_MAX), output);
     } else {
       // Negative overflow is already saturated to INT64_MIN, so we only
       // have to handle NaN and positive overflow here.
       Label notNaN;
       branchDouble(Assembler::DoubleOrdered, input, input, &notNaN);
       move64(Imm64(0), output);
       jump(rejoin);
 
       bind(&notNaN);
-      loadConstantDouble(0.0, ScratchDoubleReg);
-      branchDouble(Assembler::DoubleLessThan, input, ScratchDoubleReg, rejoin);
+      ScratchDoubleScope fpscratch(*this);
+      loadConstantDouble(0.0, fpscratch);
+      branchDouble(Assembler::DoubleLessThan, input, fpscratch, rejoin);
       sub64(Imm64(1), output);
     }
     jump(rejoin);
     return;
   }
 
   AutoHandleWasmTruncateToIntErrors traps(*this, off);
 
   // Eagerly take care of NaNs.
   branchDouble(Assembler::DoubleUnordered, input, input, &traps.inputIsNaN);
 
   // Handle special values.
   if (isUnsigned) {
-    loadConstantDouble(0.0, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg,
+    ScratchDoubleScope fpscratch(*this);
+    loadConstantDouble(0.0, fpscratch);
+    branchDouble(Assembler::DoubleGreaterThan, input, fpscratch,
                  &traps.intOverflow);
-    loadConstantDouble(-1.0, ScratchDoubleReg);
-    branchDouble(Assembler::DoubleLessThanOrEqual, input, ScratchDoubleReg,
+    loadConstantDouble(-1.0, fpscratch);
+    branchDouble(Assembler::DoubleLessThanOrEqual, input, fpscratch,
                  &traps.intOverflow);
     jump(rejoin);
     return;
   }
 
   // We've used vcvtsd2sq. The only legit value whose i64
   // truncation is INT64_MIN is double(INT64_MIN): exponent is so
   // high that the highest resolution around is much more than 1.
-  loadConstantDouble(double(int64_t(INT64_MIN)), ScratchDoubleReg);
-  branchDouble(Assembler::DoubleNotEqual, input, ScratchDoubleReg,
+  ScratchDoubleScope fpscratch(*this);
+  loadConstantDouble(double(int64_t(INT64_MIN)), fpscratch);
+  branchDouble(Assembler::DoubleNotEqual, input, fpscratch,
                &traps.intOverflow);
   jump(rejoin);
 }
 
 void MacroAssembler::oolWasmTruncateCheckF32ToI64(FloatRegister input,
                                                   Register64 output,
                                                   TruncFlags flags,
                                                   wasm::BytecodeOffset off,
@@ -924,62 +933,64 @@ void MacroAssembler::oolWasmTruncateChec
   bool isSaturating = flags & TRUNC_SATURATING;
 
   if (isSaturating) {
     if (isUnsigned) {
       // Negative overflow and NaN both are converted to 0, and the only
       // other case is positive overflow which is converted to
       // UINT64_MAX.
       Label positive;
-      loadConstantFloat32(0.0f, ScratchFloat32Reg);
-      branchFloat(Assembler::DoubleGreaterThan, input, ScratchFloat32Reg,
-                  &positive);
+      ScratchFloat32Scope fpscratch(*this);
+      loadConstantFloat32(0.0f, fpscratch);
+      branchFloat(Assembler::DoubleGreaterThan, input, fpscratch, &positive);
       move64(Imm64(0), output);
       jump(rejoin);
 
       bind(&positive);
       move64(Imm64(UINT64_MAX), output);
     } else {
       // Negative overflow is already saturated to INT64_MIN, so we only
       // have to handle NaN and positive overflow here.
       Label notNaN;
       branchFloat(Assembler::DoubleOrdered, input, input, &notNaN);
       move64(Imm64(0), output);
       jump(rejoin);
 
       bind(&notNaN);
-      loadConstantFloat32(0.0f, ScratchFloat32Reg);
-      branchFloat(Assembler::DoubleLessThan, input, ScratchFloat32Reg, rejoin);
+      ScratchFloat32Scope fpscratch(*this);
+      loadConstantFloat32(0.0f, fpscratch);
+      branchFloat(Assembler::DoubleLessThan, input, fpscratch, rejoin);
       sub64(Imm64(1), output);
     }
     jump(rejoin);
     return;
   }
 
   AutoHandleWasmTruncateToIntErrors traps(*this, off);
 
   // Eagerly take care of NaNs.
   branchFloat(Assembler::DoubleUnordered, input, input, &traps.inputIsNaN);
 
   // Handle special values.
   if (isUnsigned) {
-    loadConstantFloat32(0.0f, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleGreaterThan, input, ScratchFloat32Reg,
+    ScratchFloat32Scope fpscratch(*this);
+    loadConstantFloat32(0.0f, fpscratch);
+    branchFloat(Assembler::DoubleGreaterThan, input, fpscratch,
                 &traps.intOverflow);
-    loadConstantFloat32(-1.0f, ScratchFloat32Reg);
-    branchFloat(Assembler::DoubleLessThanOrEqual, input, ScratchFloat32Reg,
+    loadConstantFloat32(-1.0f, fpscratch);
+    branchFloat(Assembler::DoubleLessThanOrEqual, input, fpscratch,
                 &traps.intOverflow);
     jump(rejoin);
     return;
   }
 
   // We've used vcvtss2sq. See comment in outOfLineWasmTruncateDoubleToInt64.
-  loadConstantFloat32(float(int64_t(INT64_MIN)), ScratchFloat32Reg);
-  branchFloat(Assembler::DoubleNotEqual, input, ScratchFloat32Reg,
-              &traps.intOverflow);
+  ScratchFloat32Scope fpscratch(*this);
+  loadConstantFloat32(float(int64_t(INT64_MIN)), fpscratch);
+  branchFloat(Assembler::DoubleNotEqual, input, fpscratch, &traps.intOverflow);
   jump(rejoin);
 }
 
 void MacroAssembler::enterFakeExitFrameForWasm(Register cxreg, Register scratch,
                                                ExitFrameType type) {
   enterFakeExitFrame(cxreg, scratch, type);
 }
 
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -576,38 +576,42 @@ void CodeGeneratorX86::visitOutOfLineTru
     masm.jump(&fail);
   } else {
     FloatRegister temp = ToFloatRegister(ins->tempFloat());
 
     // Try to convert doubles representing integers within 2^32 of a signed
     // integer, by adding/subtracting 2^32 and then trying to convert to int32.
     // This has to be an exact conversion, as otherwise the truncation works
     // incorrectly on the modified value.
-    masm.zeroDouble(ScratchDoubleReg);
-    masm.vucomisd(ScratchDoubleReg, input);
-    masm.j(Assembler::Parity, &fail);
+    {
+      ScratchDoubleScope fpscratch(masm);
+      masm.zeroDouble(fpscratch);
+      masm.vucomisd(fpscratch, input);
+      masm.j(Assembler::Parity, &fail);
+    }
 
     {
       Label positive;
       masm.j(Assembler::Above, &positive);
 
       masm.loadConstantDouble(4294967296.0, temp);
       Label skip;
       masm.jmp(&skip);
 
       masm.bind(&positive);
       masm.loadConstantDouble(-4294967296.0, temp);
       masm.bind(&skip);
     }
 
     masm.addDouble(input, temp);
     masm.vcvttsd2si(temp, output);
-    masm.vcvtsi2sd(output, ScratchDoubleReg, ScratchDoubleReg);
+    ScratchDoubleScope fpscratch(masm);
+    masm.vcvtsi2sd(output, fpscratch, fpscratch);
 
-    masm.vucomisd(ScratchDoubleReg, temp);
+    masm.vucomisd(fpscratch, temp);
     masm.j(Assembler::Parity, &fail);
     masm.j(Assembler::Equal, ool->rejoin());
   }
 
   masm.bind(&fail);
   {
     saveVolatile(output);
 
@@ -662,38 +666,42 @@ void CodeGeneratorX86::visitOutOfLineTru
     masm.jump(&fail);
   } else {
     FloatRegister temp = ToFloatRegister(ins->tempFloat());
 
     // Try to convert float32 representing integers within 2^32 of a signed
     // integer, by adding/subtracting 2^32 and then trying to convert to int32.
     // This has to be an exact conversion, as otherwise the truncation works
     // incorrectly on the modified value.
-    masm.zeroFloat32(ScratchFloat32Reg);
-    masm.vucomiss(ScratchFloat32Reg, input);
-    masm.j(Assembler::Parity, &fail);
+    {
+      ScratchFloat32Scope fpscratch(masm);
+      masm.zeroFloat32(fpscratch);
+      masm.vucomiss(fpscratch, input);
+      masm.j(Assembler::Parity, &fail);
+    }
 
     {
       Label positive;
       masm.j(Assembler::Above, &positive);
 
       masm.loadConstantFloat32(4294967296.f, temp);
       Label skip;
       masm.jmp(&skip);
 
       masm.bind(&positive);
       masm.loadConstantFloat32(-4294967296.f, temp);
       masm.bind(&skip);
     }
 
     masm.addFloat32(input, temp);
     masm.vcvttss2si(temp, output);
-    masm.vcvtsi2ss(output, ScratchFloat32Reg, ScratchFloat32Reg);
+    ScratchFloat32Scope fpscratch(masm);
+    masm.vcvtsi2ss(output, fpscratch, fpscratch);
 
-    masm.vucomiss(ScratchFloat32Reg, temp);
+    masm.vucomiss(fpscratch, temp);
     masm.j(Assembler::Parity, &fail);
     masm.j(Assembler::Equal, ool->rejoin());
   }
 
   masm.bind(&fail);
   {
     saveVolatile(output);
 
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -36,25 +36,24 @@ void MacroAssembler::moveDoubleToGPR64(F
     vmovd(src, dest.low);
     moveDouble(src, scratch);
     vpsrldq(Imm32(4), scratch, scratch);
     vmovd(scratch, dest.high);
   }
 }
 
 void MacroAssembler::moveGPR64ToDouble(Register64 src, FloatRegister dest) {
-  ScratchDoubleScope scratch(*this);
-
   if (Assembler::HasSSE41()) {
     vmovd(src.low, dest);
     vpinsrd(1, src.high, dest, dest);
   } else {
+    ScratchDoubleScope fpscratch(*this);
     vmovd(src.low, dest);
-    vmovd(src.high, ScratchDoubleReg);
-    vunpcklps(ScratchDoubleReg, dest, dest);
+    vmovd(src.high, fpscratch);
+    vunpcklps(fpscratch, dest, dest);
   }
 }
 
 void MacroAssembler::move64To32(Register64 src, Register dest) {
   if (src.low != dest) {
     movl(src.low, dest);
   }
 }
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -916,37 +916,39 @@ void MacroAssembler::wasmAtomicFetchOp64
 void MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input,
                                                 Register output,
                                                 bool isSaturating,
                                                 Label* oolEntry) {
   Label done;
   vcvttsd2si(input, output);
   branch32(Assembler::Condition::NotSigned, output, Imm32(0), &done);
 
-  loadConstantDouble(double(int32_t(0x80000000)), ScratchDoubleReg);
-  addDouble(input, ScratchDoubleReg);
-  vcvttsd2si(ScratchDoubleReg, output);
+  ScratchDoubleScope fpscratch(*this);
+  loadConstantDouble(double(int32_t(0x80000000)), fpscratch);
+  addDouble(input, fpscratch);
+  vcvttsd2si(fpscratch, output);
 
   branch32(Assembler::Condition::Signed, output, Imm32(0), oolEntry);
   or32(Imm32(0x80000000), output);
 
   bind(&done);
 }
 
 void MacroAssembler::wasmTruncateFloat32ToUInt32(FloatRegister input,
                                                  Register output,
                                                  bool isSaturating,
                                                  Label* oolEntry) {
   Label done;
   vcvttss2si(input, output);
   branch32(Assembler::Condition::NotSigned, output, Imm32(0), &done);
 
-  loadConstantFloat32(float(int32_t(0x80000000)), ScratchFloat32Reg);
-  addFloat32(input, ScratchFloat32Reg);
-  vcvttss2si(ScratchFloat32Reg, output);
+  ScratchFloat32Scope fpscratch(*this);
+  loadConstantFloat32(float(int32_t(0x80000000)), fpscratch);
+  addFloat32(input, fpscratch);
+  vcvttss2si(fpscratch, output);
 
   branch32(Assembler::Condition::Signed, output, Imm32(0), oolEntry);
   or32(Imm32(0x80000000), output);
 
   bind(&done);
 }
 
 void MacroAssembler::wasmTruncateDoubleToInt64(
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -782,40 +782,40 @@ class MacroAssemblerX86 : public MacroAs
   }
   void unboxObject(const BaseIndex& src, Register dest) {
     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
   }
   void unboxDouble(const Address& src, FloatRegister dest) {
     loadDouble(Operand(src), dest);
   }
   void unboxDouble(const ValueOperand& src, FloatRegister dest) {
-    MOZ_ASSERT(dest != ScratchDoubleReg);
     if (Assembler::HasSSE41()) {
       vmovd(src.payloadReg(), dest);
       vpinsrd(1, src.typeReg(), dest, dest);
     } else {
+      ScratchDoubleScope fpscratch(asMasm());
       vmovd(src.payloadReg(), dest);
-      vmovd(src.typeReg(), ScratchDoubleReg);
-      vunpcklps(ScratchDoubleReg, dest, dest);
+      vmovd(src.typeReg(), fpscratch);
+      vunpcklps(fpscratch, dest, dest);
     }
   }
   void unboxDouble(const Operand& payload, const Operand& type,
                    Register scratch, FloatRegister dest) {
-    MOZ_ASSERT(dest != ScratchDoubleReg);
     if (Assembler::HasSSE41()) {
       movl(payload, scratch);
       vmovd(scratch, dest);
       movl(type, scratch);
       vpinsrd(1, scratch, dest, dest);
     } else {
+      ScratchDoubleScope fpscratch(asMasm());
       movl(payload, scratch);
       vmovd(scratch, dest);
       movl(type, scratch);
-      vmovd(scratch, ScratchDoubleReg);
-      vunpcklps(ScratchDoubleReg, dest, dest);
+      vmovd(scratch, fpscratch);
+      vunpcklps(fpscratch, dest, dest);
     }
   }
   inline void unboxValue(const ValueOperand& src, AnyRegister dest,
                          JSValueType type);
   void unboxPrivate(const ValueOperand& src, Register dest) {
     if (src.payloadReg() != dest) {
       movl(src.payloadReg(), dest);
     }
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -129,28 +129,32 @@ static void SetupABIArguments(MacroAssem
 #endif
             break;
           }
           case MIRType::Pointer:
             masm.loadPtr(src, scratch);
             masm.storePtr(scratch, Address(masm.getStackPointer(),
                                            iter->offsetFromArgBase()));
             break;
-          case MIRType::Double:
-            masm.loadDouble(src, ScratchDoubleReg);
+          case MIRType::Double: {
+            ScratchDoubleScope fpscratch(masm);
+            masm.loadDouble(src, fpscratch);
             masm.storeDouble(
-                ScratchDoubleReg,
+                fpscratch,
                 Address(masm.getStackPointer(), iter->offsetFromArgBase()));
             break;
-          case MIRType::Float32:
-            masm.loadFloat32(src, ScratchFloat32Reg);
+          }
+          case MIRType::Float32: {
+            ScratchFloat32Scope fpscratch(masm);
+            masm.loadFloat32(src, fpscratch);
             masm.storeFloat32(
-                ScratchFloat32Reg,
+                fpscratch,
                 Address(masm.getStackPointer(), iter->offsetFromArgBase()));
             break;
+          }
           default:
             MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
                 "unexpected stack arg type");
         }
         break;
       case ABIArg::Uninitialized:
         MOZ_CRASH("Uninitialized ABIArg kind");
     }
@@ -730,25 +734,29 @@ static bool GenerateJitEntry(MacroAssemb
   // Store the return value in the JSReturnOperand.
   switch (fe.funcType().ret().code()) {
     case ExprType::Void:
       masm.moveValue(UndefinedValue(), JSReturnOperand);
       break;
     case ExprType::I32:
       masm.boxNonDouble(JSVAL_TYPE_INT32, ReturnReg, JSReturnOperand);
       break;
-    case ExprType::F32:
+    case ExprType::F32: {
       masm.canonicalizeFloat(ReturnFloat32Reg);
       masm.convertFloat32ToDouble(ReturnFloat32Reg, ReturnDoubleReg);
-      masm.boxDouble(ReturnDoubleReg, JSReturnOperand, ScratchDoubleReg);
+      ScratchDoubleScope fpscratch(masm);
+      masm.boxDouble(ReturnDoubleReg, JSReturnOperand, fpscratch);
       break;
-    case ExprType::F64:
+    }
+    case ExprType::F64: {
       masm.canonicalizeDouble(ReturnDoubleReg);
-      masm.boxDouble(ReturnDoubleReg, JSReturnOperand, ScratchDoubleReg);
+      ScratchDoubleScope fpscratch(masm);
+      masm.boxDouble(ReturnDoubleReg, JSReturnOperand, fpscratch);
       break;
+    }
     case ExprType::Ref:
       MOZ_CRASH("return ref in jitentry NYI");
       break;
     case ExprType::AnyRef:
       MOZ_CRASH("return anyref in jitentry NYI");
       break;
     case ExprType::I64:
       MOZ_CRASH("unexpected return type when calling from ion to wasm");
@@ -894,24 +902,28 @@ void wasm::GenerateDirectCallFromJit(Mac
                 "unexpected MIR type for a float register in wasm fast call");
         }
         break;
       case JitCallStackArg::Tag::Address: {
         // The address offsets were valid *before* we pushed our frame.
         Address src = stackArg.addr();
         src.offset += masm.framePushed() - framePushedAtStart;
         switch (iter.mirType()) {
-          case MIRType::Double:
-            masm.loadDouble(src, ScratchDoubleReg);
-            masm.storeDouble(ScratchDoubleReg, dst);
+          case MIRType::Double: {
+            ScratchDoubleScope fpscratch(masm);
+            masm.loadDouble(src, fpscratch);
+            masm.storeDouble(fpscratch, dst);
             break;
-          case MIRType::Float32:
-            masm.loadFloat32(src, ScratchFloat32Reg);
-            masm.storeFloat32(ScratchFloat32Reg, dst);
+          }
+          case MIRType::Float32: {
+            ScratchFloat32Scope fpscratch(masm);
+            masm.loadFloat32(src, fpscratch);
+            masm.storeFloat32(fpscratch, dst);
             break;
+          }
           case MIRType::Int32:
             masm.loadPtr(src, scratch);
             masm.storePtr(scratch, dst);
             break;
           default:
             MOZ_CRASH("unexpected MIR type for a stack slot in wasm fast call");
         }
         break;
@@ -988,22 +1000,24 @@ static void StackCopy(MacroAssembler& ma
     Register64 scratch64(scratch);
     masm.load64(src, scratch64);
     masm.store64(scratch64, dst);
 #endif
   } else if (type == MIRType::Pointer) {
     masm.loadPtr(src, scratch);
     masm.storePtr(scratch, dst);
   } else if (type == MIRType::Float32) {
-    masm.loadFloat32(src, ScratchFloat32Reg);
-    masm.storeFloat32(ScratchFloat32Reg, dst);
+    ScratchFloat32Scope fpscratch(masm);
+    masm.loadFloat32(src, fpscratch);
+    masm.storeFloat32(fpscratch, dst);
   } else {
     MOZ_ASSERT(type == MIRType::Double);
-    masm.loadDouble(src, ScratchDoubleReg);
-    masm.storeDouble(ScratchDoubleReg, dst);
+    ScratchDoubleScope fpscratch(masm);
+    masm.loadDouble(src, fpscratch);
+    masm.storeDouble(fpscratch, dst);
   }
 }
 
 typedef bool ToValue;
 
 static void FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args,
                               unsigned argOffset,
                               unsigned offsetToCallerStackArgs,
@@ -1044,33 +1058,37 @@ static void FillArgumentArray(MacroAssem
         break;
 #endif
       case ABIArg::FPU: {
         MOZ_ASSERT(IsFloatingPointType(type));
         FloatRegister srcReg = i->fpu();
         if (type == MIRType::Double) {
           if (toValue) {
             // Preserve the NaN pattern in the input.
-            masm.moveDouble(srcReg, ScratchDoubleReg);
-            srcReg = ScratchDoubleReg;
-            masm.canonicalizeDouble(srcReg);
+            ScratchDoubleScope fpscratch(masm);
+            masm.moveDouble(srcReg, fpscratch);
+            masm.canonicalizeDouble(fpscratch);
+            masm.storeDouble(fpscratch, dst);
+          } else {
+            masm.storeDouble(srcReg, dst);
           }
-          masm.storeDouble(srcReg, dst);
         } else {
           MOZ_ASSERT(type == MIRType::Float32);
           if (toValue) {
             // JS::Values can't store Float32, so convert to a Double.
-            masm.convertFloat32ToDouble(srcReg, ScratchDoubleReg);
-            masm.canonicalizeDouble(ScratchDoubleReg);
-            masm.storeDouble(ScratchDoubleReg, dst);
+            ScratchDoubleScope fpscratch(masm);
+            masm.convertFloat32ToDouble(srcReg, fpscratch);
+            masm.canonicalizeDouble(fpscratch);
+            masm.storeDouble(fpscratch, dst);
           } else {
             // Preserve the NaN pattern in the input.
-            masm.moveFloat32(srcReg, ScratchFloat32Reg);
-            masm.canonicalizeFloat(ScratchFloat32Reg);
-            masm.storeFloat32(ScratchFloat32Reg, dst);
+            ScratchFloat32Scope fpscratch(masm);
+            masm.moveFloat32(srcReg, fpscratch);
+            masm.canonicalizeFloat(fpscratch);
+            masm.storeFloat32(fpscratch, dst);
           }
         }
         break;
       }
       case ABIArg::Stack: {
         Address src(masm.getStackPointer(),
                     offsetToCallerStackArgs + i->offsetFromArgBase());
         if (toValue) {
@@ -1079,24 +1097,26 @@ static void FillArgumentArray(MacroAssem
             masm.storeValue(JSVAL_TYPE_INT32, scratch, dst);
           } else if (type == MIRType::Int64) {
             // We can't box int64 into Values (yet).
             masm.breakpoint();
           } else if (type == MIRType::Pointer) {
             MOZ_CRASH("generating a jit exit for anyref NYI");
           } else {
             MOZ_ASSERT(IsFloatingPointType(type));
+            ScratchDoubleScope dscratch(masm);
+            FloatRegister fscratch = dscratch.asSingle();
             if (type == MIRType::Float32) {
-              masm.loadFloat32(src, ScratchFloat32Reg);
-              masm.convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
+              masm.loadFloat32(src, fscratch);
+              masm.convertFloat32ToDouble(fscratch, dscratch);
             } else {
-              masm.loadDouble(src, ScratchDoubleReg);
+              masm.loadDouble(src, dscratch);
             }
-            masm.canonicalizeDouble(ScratchDoubleReg);
-            masm.storeDouble(ScratchDoubleReg, dst);
+            masm.canonicalizeDouble(dscratch);
+            masm.storeDouble(dscratch, dst);
           }
         } else {
           StackCopy(masm, type, scratch, src, dst);
         }
         break;
       }
       case ABIArg::Uninitialized:
         MOZ_CRASH("Uninitialized ABIArg kind");