Merge inbound to mozilla-central. a=merge
authorOana Pop Rus <opoprus@mozilla.com>
Fri, 01 Feb 2019 11:37:15 +0200
changeset 456401 d58901c5036ffa06da6144f22a31479116ee0835
parent 456392 9e6217a541aa84c3bd635459d842b6fbfed311de (current diff)
parent 456400 a5f0e7af6f5c9b45e6360ae86005ee75b2a1bb63 (diff)
child 456402 b62cac80b403038aa9c9f7da5a987dc04838121c
push id19
push usermdeboer@mozilla.com
push dateFri, 01 Feb 2019 10:05:45 +0000
reviewersmerge
milestone67.0a1
Merge inbound to mozilla-central. a=merge
dom/base/ContentBlockingLog.h
--- 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");
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -41,18 +41,22 @@ class ADBProcess(object):
         if not self.stdout_file or self.stdout_file.closed:
             content = ""
         else:
             self.stdout_file.seek(0, os.SEEK_SET)
             content = self.stdout_file.read().rstrip()
         return content
 
     def __str__(self):
+        # Remove -s <serialno> from the error message to allow bug suggestions
+        # to be independent of the individual failing device.
+        arg_string = ' '.join(self.args)
+        arg_string = re.sub(' -s \w+', '', arg_string)
         return ('args: %s, exitcode: %s, stdout: %s' % (
-            ' '.join(self.args), self.exitcode, self.stdout))
+            arg_string, self.exitcode, self.stdout))
 
 # ADBError, ADBRootError, and ADBTimeoutError are treated
 # differently in order that unhandled ADBRootErrors and
 # ADBTimeoutErrors can be handled distinctly from ADBErrors.
 
 
 class ADBError(Exception):
     """ADBError is raised in situations where a command executed on a
--- a/testing/mozbase/mozdevice/setup.py
+++ b/testing/mozbase/mozdevice/setup.py
@@ -3,17 +3,17 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_NAME = 'mozdevice'
-PACKAGE_VERSION = '2.0'
+PACKAGE_VERSION = '2.0.1'
 
 deps = ['mozlog >= 3.0']
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description="Mozilla-authored device management",
       long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html",
       classifiers=['Programming Language :: Python :: 2.7',
--- a/testing/mozharness/mozharness/mozilla/testing/android.py
+++ b/testing/mozharness/mozharness/mozilla/testing/android.py
@@ -318,18 +318,21 @@ class AndroidMixin(object):
     def install_apk(self, apk):
         """
            Install the specified apk.
         """
         import mozdevice
         try:
             self.device.install_app(apk)
         except (mozdevice.ADBError, mozdevice.ADBTimeoutError):
-            self.fatal('INFRA-ERROR: Failed to install %s on %s' %
-                       (self.installer_path, self.device_name),
+            self.info('Failed to install %s on %s' %
+                      (self.installer_path, self.device_name),
+                      exc_info=1)
+            self.fatal('INFRA-ERROR: Failed to install %s' %
+                       self.installer_path,
                        EXIT_STATUS_DICT[TBPL_RETRY])
 
     def is_boot_completed(self):
         import mozdevice
         try:
             out = self.device.get_prop('sys.boot_completed', timeout=30)
             if out.strip() == '1':
                 return True
--- a/testing/raptor/raptor/output.py
+++ b/testing/raptor/raptor/output.py
@@ -27,28 +27,29 @@ class Output(object):
         """
         self.results = results
         self.summarized_results = {}
         self.supporting_data = supporting_data
         self.summarized_supporting_data = []
         self.summarized_screenshots = []
         self.subtest_alert_on = subtest_alert_on
 
-    def summarize(self):
+    def summarize(self, test_names):
         suites = []
         test_results = {
             'framework': {
                 'name': 'raptor',
             },
             'suites': suites,
         }
 
         # check if we actually have any results
         if len(self.results) == 0:
-            LOG.error("error: no raptor test results found!")
+            LOG.error("error: no raptor test results found for %s" %
+                      ', '.join(test_names))
             return
 
         for test in self.results:
             vals = []
             subtests = []
             suite = {
                 'name': test.name,
                 'type': test.type,
@@ -129,17 +130,18 @@ class Output(object):
                     subtests, vals = self.parseAssortedDomOutput(test)
                 elif 'wasm-misc' in test.measurements:
                     subtests, vals = self.parseWASMMiscOutput(test)
                 elif 'wasm-godot' in test.measurements:
                     subtests, vals = self.parseWASMGodotOutput(test)
                 suite['subtests'] = subtests
 
             else:
-                LOG.error("output.summarize received unsupported test results type")
+                LOG.error("output.summarize received unsupported test results type for %s" %
+                          test.name)
                 return
 
             # for benchmarks there is generally  more than one subtest in each cycle
             # and a benchmark-specific formula is needed to calculate the final score
 
             # for pageload tests, if there are > 1 subtests here, that means there
             # were multiple measurements captured in each single pageload; we want
             # to get the mean of those values and report 1 overall 'suite' value
@@ -597,20 +599,21 @@ class Output(object):
             </tr>""" % (screenshot['test_name'],
                         screenshot['page_cycle'],
                         screenshot['screenshot'],
                         screenshot['test_name'],
                         screenshot['page_cycle']))
 
         self.summarized_screenshots.append("""</table></body> </html>""")
 
-    def output(self):
+    def output(self, test_names):
         """output to file and perfherder data json """
         if self.summarized_results == {}:
-            LOG.error("error: no summarized raptor results found!")
+            LOG.error("error: no summarized raptor results found for %s" %
+                      ', '.join(test_names))
             return False
 
         if os.environ['MOZ_UPLOAD_DIR']:
             # i.e. testing/mozharness/build/raptor.json locally; in production it will
             # be at /tasks/task_*/build/ (where it will be picked up by mozharness later
             # and made into a tc artifact accessible in treeherder as perfherder-data.json)
             results_path = os.path.join(os.path.dirname(os.environ['MOZ_UPLOAD_DIR']),
                                         'raptor.json')
@@ -645,28 +648,29 @@ class Output(object):
             LOG.info("gecko profiling enabled - not posting results for perfherder")
 
         json.dump(self.summarized_results, open(results_path, 'w'), indent=2,
                   sort_keys=True)
         LOG.info("results can also be found locally at: %s" % results_path)
 
         return True
 
-    def output_supporting_data(self):
+    def output_supporting_data(self, test_names):
         '''
         Supporting data was gathered outside of the main raptor test; it has already
         been summarized, now output it appropriately.
 
         We want to output supporting data in a completely separate perfherder json blob and
         in a corresponding file artifact. This way supporting data can be ingested as it's own
         test suite in perfherder and alerted upon if desired. Kept outside of the test results
         from the actual Raptor test that was ran when the supporting data was gathered.
         '''
         if len(self.summarized_supporting_data) == 0:
-            LOG.error("error: no summarized supporting data found!")
+            LOG.error("error: no summarized supporting data found for %s" %
+                      ', '.join(test_names))
             return False
 
         for next_data_set in self.summarized_supporting_data:
             data_type = next_data_set['suites'][0]['type']
 
             if os.environ['MOZ_UPLOAD_DIR']:
                 # i.e. testing/mozharness/build/raptor.json locally; in production it will
                 # be at /tasks/task_*/build/ (where it will be picked up by mozharness later
--- a/testing/raptor/raptor/raptor.py
+++ b/testing/raptor/raptor/raptor.py
@@ -459,37 +459,41 @@ class Raptor(object):
         upload_dir = os.getenv('MOZ_UPLOAD_DIR')
         if not upload_dir:
             self.log.critical("Profiling ignored because MOZ_UPLOAD_DIR was not set")
         else:
             self.gecko_profiler = GeckoProfile(upload_dir,
                                                self.config,
                                                test)
 
-    def process_results(self):
+    def process_results(self, test_names):
         # when running locally output results in build/raptor.json; when running
         # in production output to a local.json to be turned into tc job artifact
         if self.config.get('run_local', False):
             if 'MOZ_DEVELOPER_REPO_DIR' in os.environ:
                 raptor_json_path = os.path.join(os.environ['MOZ_DEVELOPER_REPO_DIR'],
                                                 'testing', 'mozharness', 'build', 'raptor.json')
             else:
                 raptor_json_path = os.path.join(here, 'raptor.json')
         else:
             raptor_json_path = os.path.join(os.getcwd(), 'local.json')
 
         self.config['raptor_json_path'] = raptor_json_path
-        return self.results_handler.summarize_and_output(self.config)
+        return self.results_handler.summarize_and_output(self.config, test_names)
 
     def get_page_timeout_list(self):
         return self.results_handler.page_timeout_list
 
     def check_for_crashes(self):
         if self.config['app'] in ["geckoview", "fennec"]:
+            # Turn off verbose to prevent logcat from being inserted into the main log.
+            verbose = self.device._verbose
+            self.device._verbose = False
             logcat = self.device.get_logcat()
+            self.device._verbose = verbose
             if logcat:
                 if mozcrash.check_for_java_exception(logcat, "raptor"):
                     return
             try:
                 dump_dir = tempfile.mkdtemp()
                 remote_dir = posixpath.join(self.device_profile, 'minidumps')
                 if not self.device.is_dir(remote_dir):
                     self.log.error("No crash directory (%s) found on remote device" % remote_dir)
@@ -584,16 +588,17 @@ def main(args=sys.argv[1:]):
     if args.debug_mode:
         LOG.info("debug-mode enabled")
 
     LOG.info("received command line arguments: %s" % str(args))
 
     # if a test name specified on command line, and it exists, just run that one
     # otherwise run all available raptor tests that are found for this browser
     raptor_test_list = get_raptor_test_list(args, mozinfo.os)
+    raptor_test_names = [raptor_test['name'] for raptor_test in raptor_test_list]
 
     # ensure we have at least one valid test to run
     if len(raptor_test_list) == 0:
         LOG.critical("abort: no tests found")
         sys.exit(1)
 
     LOG.info("raptor tests scheduled to run:")
     for next_test in raptor_test_list:
@@ -617,22 +622,23 @@ def main(args=sys.argv[1:]):
     for next_test in raptor_test_list:
         if 'page_timeout' not in next_test.keys():
             next_test['page_timeout'] = 120000
         if 'page_cycles' not in next_test.keys():
             next_test['page_cycles'] = 1
 
         raptor.run_test(next_test, timeout=int(next_test['page_timeout']))
 
-    success = raptor.process_results()
+    success = raptor.process_results(raptor_test_names)
     raptor.clean_up()
 
     if not success:
         # didn't get test results; test timed out or crashed, etc. we want job to fail
-        LOG.critical("TEST-UNEXPECTED-FAIL: no raptor test results were found")
+        LOG.critical("TEST-UNEXPECTED-FAIL: no raptor test results were found for %s" %
+                     ', '.join(raptor_test_names))
         os.sys.exit(1)
 
     # if we have results but one test page timed out (i.e. one tp6 test page didn't load
     # but others did) we still dumped PERFHERDER_DATA for the successfull pages but we
     # want the overall test job to marked as a failure
     pages_that_timed_out = raptor.get_page_timeout_list()
     if len(pages_that_timed_out) > 0:
         for _page in pages_that_timed_out:
--- a/testing/raptor/raptor/results.py
+++ b/testing/raptor/raptor/results.py
@@ -61,27 +61,27 @@ class RaptorResultsHandler():
                                'proportional': proportional}}
         '''
         LOG.info("RaptorResultsHandler.add_supporting_data received %s data"
                  % supporting_data['type'])
         if self.supporting_data is None:
             self.supporting_data = []
         self.supporting_data.append(supporting_data)
 
-    def summarize_and_output(self, test_config):
+    def summarize_and_output(self, test_config, test_names):
         # summarize the result data, write to file and output PERFHERDER_DATA
         LOG.info("summarizing raptor test results")
         output = Output(self.results, self.supporting_data, test_config['subtest_alert_on'])
-        output.summarize()
+        output.summarize(test_names)
         output.summarize_screenshots(self.images)
         # only dump out supporting data (i.e. power) if actual Raptor test completed
         if self.supporting_data is not None and len(self.results) != 0:
             output.summarize_supporting_data()
-            output.output_supporting_data()
-        return output.output()
+            output.output_supporting_data(test_names)
+        return output.output(test_names)
 
 
 class RaptorTestResult():
     """Single Raptor test result class"""
 
     def __init__(self, test_result_json):
         self.extra_options = []
         # convert test result json/dict (from control server) to test result object instance
--- a/toolkit/mozapps/update/nsIUpdateService.idl
+++ b/toolkit/mozapps/update/nsIUpdateService.idl
@@ -394,24 +394,19 @@ interface nsIApplicationUpdateService : 
 /**
  * An interface describing a component which handles the job of processing
  * an update after it's been downloaded.
  */
 [scriptable, uuid(74439497-d796-4915-8cef-3dfe43027e4d)]
 interface nsIUpdateProcessor : nsISupports
 {
   /**
-   * Processes the update which has been downloaded.
-   * This happens without restarting the application.
-   * On Windows, this can also be used for switching to an applied
-   * update request.
-   * @param update The update being applied, or null if this is a switch
-   *               to updated application request.
+   * Stages an update while the application is running.
    */
-  void processUpdate(in nsIUpdate update);
+  void processUpdate();
 
   /**
    * Attempts to fix the permissions of the update directory. This can be done
    * in two ways. Firefox can attempt to fix the permissions itself, or it can
    * call into the maintenance service to request that it attempt to fix the
    * permissions.
    *
    * Fixing the permissions can take some time, so this work is all done off of
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -4006,18 +4006,17 @@ Downloader.prototype = {
         state == STATE_PENDING_ELEVATE) {
       if (getCanStageUpdates()) {
         LOG("Downloader:onStopRequest - attempting to stage update: " +
             this._update.name);
         gUpdateFileWriteInfo = {phase: "stage", failure: false};
         // Stage the update
         try {
           Cc["@mozilla.org/updates/update-processor;1"].
-            createInstance(Ci.nsIUpdateProcessor).
-            processUpdate(this._update);
+            createInstance(Ci.nsIUpdateProcessor).processUpdate();
         } catch (e) {
           // Fail gracefully in case the application does not support the update
           // processor service.
           LOG("Downloader:onStopRequest - failed to stage update. Exception: " +
               e);
           if (this.background) {
             shouldShowPrompt = true;
           }
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -2075,18 +2075,17 @@ function stageUpdate(aCheckSvcLog) {
 
   Services.obs.addObserver(gUpdateStagedObserver, "update-staged");
 
   setAppBundleModTime();
   setEnvironment();
   try {
     // Stage the update.
     Cc["@mozilla.org/updates/update-processor;1"].
-      createInstance(Ci.nsIUpdateProcessor).
-      processUpdate(gUpdateManager.activeUpdate);
+      createInstance(Ci.nsIUpdateProcessor).processUpdate();
   } catch (e) {
     Assert.ok(false,
               "error thrown while calling processUpdate, exception: " + e);
   }
 
   // The environment is not reset here because processUpdate in
   // nsIUpdateProcessor uses a new thread and clearing the environment
   // immediately after calling processUpdate can clear the environment before
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -783,17 +783,17 @@ nsresult ProcessUpdates(nsIFile *greDir,
 
 NS_IMPL_ISUPPORTS(nsUpdateProcessor, nsIUpdateProcessor)
 
 nsUpdateProcessor::nsUpdateProcessor() : mUpdaterPID(0) {}
 
 nsUpdateProcessor::~nsUpdateProcessor() {}
 
 NS_IMETHODIMP
-nsUpdateProcessor::ProcessUpdate(nsIUpdate *aUpdate) {
+nsUpdateProcessor::ProcessUpdate() {
   nsresult rv;
 
   nsCOMPtr<nsIProperties> ds =
       do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIFile> exeFile;
   rv = ds->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
--- a/toolkit/xre/nsUpdateDriver.h
+++ b/toolkit/xre/nsUpdateDriver.h
@@ -60,32 +60,30 @@ class nsUpdateProcessor final : public n
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIUPDATEPROCESSOR
 
  private:
   ~nsUpdateProcessor();
 
   struct StagedUpdateInfo {
-    StagedUpdateInfo() : mArgc(0), mArgv(nullptr), mIsOSUpdate(false) {}
+    StagedUpdateInfo() : mArgc(0), mArgv(nullptr) {}
     ~StagedUpdateInfo() {
       for (int i = 0; i < mArgc; ++i) {
         delete[] mArgv[i];
       }
       delete[] mArgv;
     }
 
     nsCOMPtr<nsIFile> mGREDir;
     nsCOMPtr<nsIFile> mAppDir;
     nsCOMPtr<nsIFile> mUpdateRoot;
-    nsCOMPtr<nsIFile> mOSApplyToDir;
     int mArgc;
     char **mArgv;
     nsCString mAppVersion;
-    bool mIsOSUpdate;
   };
 
  private:
   void StartStagedUpdate();
   void WaitForProcess();
   void UpdateDone();
   void ShutdownWatcherThread();