commit 61531ae59512cb9cce8e15f811456c0d986d001e
parent 1abede9c2655529600e24ca666bd03f3ec788a26
Author: Cristina Horotan <chorotan@mozilla.com>
Date: Sat, 13 Dec 2025 00:23:27 +0200
Revert "Bug 1992240 - wasm: Fix JIT entry when negative denormal is used without denormal support. r=jandem" for causing SM failures on RegisterSets.h
This reverts commit dddc9fc62a56f7286db6d09c89078bbf0c5dea90.
Revert "Bug 1992240 - Rename masm.canonicalizeDouble/Float. r=jandem"
This reverts commit af7592e9e83b84cf5af6555c246d62c562817088.
Revert "Bug 1992240 - wasm: Revert Bug 1977692. r=bvisness"
This reverts commit 6eea065a3b9c8dd1a7fbc716f9ff67db393f4413.
Diffstat:
10 files changed, 44 insertions(+), 91 deletions(-)
diff --git a/js/src/jit-test/lib/wasm.js b/js/src/jit-test/lib/wasm.js
@@ -488,7 +488,6 @@ let WasmNonAnyrefValues = [
{x:1337},
["abracadabra"],
13.37,
- -0,
0x7fffffff + 0.1,
-0x7fffffff - 0.1,
0x80000000 + 0.1,
diff --git a/js/src/jit-test/tests/auto-regress/bug1940716.js b/js/src/jit-test/tests/auto-regress/bug1940716.js
@@ -1,4 +1,4 @@
-// |jit-test| --disable-main-thread-denormals; skip-if: !getBuildConfiguration("can-disable-main-thread-denormals") || !wasmIsSupported();
+// |jit-test| --disable-main-thread-denormals; skip-if: !getBuildConfiguration("can-disable-main-thread-denormals") || !wasmIsSupported() || (getBuildConfiguration("osx") && getBuildConfiguration("arm64"));
function a(b) {
c = new WebAssembly.Module(b);
@@ -7,9 +7,7 @@ function a(b) {
function d(e) {
return a(wasmTextToBinary(e));
}
+f = [ , Number.MIN_VALUE ]
let { refTest } = d(`(func (export "refTest") (param externref))`).exports;
-
-// Ensure there are enough values to trigger a wasm JIT entry
-f = Array(16).fill([Number.MIN_VALUE, -Number.MIN_VALUE]).flat();
for (h of f)
refTest(h);
diff --git a/js/src/jit-test/tests/wasm/gc/i31ref.js b/js/src/jit-test/tests/wasm/gc/i31ref.js
@@ -1,3 +1,9 @@
+// -0 is a valid value with which to create an i31ref, but because it
+// roundtrips to +0, it wrecks a lot of our WASM tests (which use Object.is for
+// comparison). Therefore we don't include -0 in the main list, and deal with
+// that complexity in this file specifically.
+WasmI31refValues.push(-0);
+
let InvalidI31Values = [
null,
Number.EPSILON,
@@ -5,8 +11,9 @@ let InvalidI31Values = [
Number.MIN_SAFE_INTEGER,
Number.MIN_VALUE,
Number.MAX_VALUE,
+ Infinity,
+ -Infinity,
Number.NaN,
- -0,
// Number objects are not coerced
...WasmI31refValues.map(n => new Number(n)),
// Non-integers are not valid
@@ -95,16 +102,16 @@ for (let i of InvalidI31Values) {
// Test that we can roundtrip 31-bit integers through the i31ref type
// faithfully.
for (let i of WasmI31refValues) {
- assertEq(refI31(i), i);
- assertEq(refI31Identity(i), i);
+ assertEq(refI31(i), Object.is(i, -0) ? 0 : i);
+ assertEq(refI31Identity(i), Object.is(i, -0) ? 0 : i);
assertEq(i31GetU(i), valueAsI31GetU(i));
- assertEq(i31GetS(i), i);
+ assertEq(i31GetS(i), Object.is(i, -0) ? 0 : i);
}
// Test that i31ref values are truncated when given a 32-bit value
for (let i of WasmI31refValues) {
let adjusted = i | 0x80000000;
- assertEq(refI31(adjusted), i);
+ assertEq(refI31(adjusted), Object.is(i, -0) ? 0 : i);
}
// Test that comparing identical i31 values works
diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp
@@ -7614,7 +7614,7 @@ bool CacheIRCompiler::emitStoreTypedArrayElement(ObjOperandId objId,
// Canonicalize floating point values for differential testing.
if (js::SupportDifferentialTesting()) {
- masm.canonicalizeDoubleNaN(floatScratch0);
+ masm.canonicalizeDouble(floatScratch0);
}
masm.storeToTypedFloatArray(elementType, floatScratch0, dest, temp,
@@ -7940,7 +7940,7 @@ bool CacheIRCompiler::emitLoadDataViewValueResult(
FloatRegister scratchFloat32 = floatScratch0.get().asSingle();
masm.moveGPRToFloat16(outputScratch, scratchFloat32, scratch2,
liveVolatileRegs());
- masm.canonicalizeFloatNaN(scratchFloat32);
+ masm.canonicalizeFloat(scratchFloat32);
masm.convertFloat32ToDouble(scratchFloat32, floatScratch0);
masm.boxDouble(floatScratch0, output.valueReg(), floatScratch0);
break;
@@ -7948,14 +7948,14 @@ bool CacheIRCompiler::emitLoadDataViewValueResult(
case Scalar::Float32: {
FloatRegister scratchFloat32 = floatScratch0.get().asSingle();
masm.moveGPRToFloat32(outputScratch, scratchFloat32);
- masm.canonicalizeFloatNaN(scratchFloat32);
+ masm.canonicalizeFloat(scratchFloat32);
masm.convertFloat32ToDouble(scratchFloat32, floatScratch0);
masm.boxDouble(floatScratch0, output.valueReg(), floatScratch0);
break;
}
case Scalar::Float64:
masm.moveGPR64ToDouble(outputReg64, floatScratch0);
- masm.canonicalizeDoubleNaN(floatScratch0);
+ masm.canonicalizeDouble(floatScratch0);
masm.boxDouble(floatScratch0, output.valueReg(), floatScratch0);
break;
case Scalar::BigInt64:
@@ -8134,7 +8134,7 @@ bool CacheIRCompiler::emitStoreDataViewValueResult(
// Canonicalize floating point values for differential testing.
if (Scalar::isFloatingType(elementType) && js::SupportDifferentialTesting()) {
- masm.canonicalizeDoubleNaN(floatScratch0);
+ masm.canonicalizeDouble(floatScratch0);
}
// Load the value into a gpr register.
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
@@ -19431,15 +19431,15 @@ void CodeGenerator::visitLoadDataViewElement(LLoadDataViewElement* lir) {
break;
case Scalar::Float16:
masm.moveGPRToFloat16(temp1, out.fpu(), temp2, volatileRegs);
- masm.canonicalizeFloatNaN(out.fpu());
+ masm.canonicalizeFloat(out.fpu());
break;
case Scalar::Float32:
masm.moveGPRToFloat32(temp1, out.fpu());
- masm.canonicalizeFloatNaN(out.fpu());
+ masm.canonicalizeFloat(out.fpu());
break;
case Scalar::Float64:
masm.moveGPR64ToDouble(temp64, out.fpu());
- masm.canonicalizeDoubleNaN(out.fpu());
+ masm.canonicalizeDouble(out.fpu());
break;
case Scalar::Int8:
case Scalar::Uint8:
@@ -22880,14 +22880,14 @@ void CodeGenerator::visitCanonicalizeNaND(LCanonicalizeNaND* ins) {
auto output = ToFloatRegister(ins->output());
MOZ_ASSERT(output == ToFloatRegister(ins->input()));
- masm.canonicalizeDoubleNaN(output);
+ masm.canonicalizeDouble(output);
}
void CodeGenerator::visitCanonicalizeNaNF(LCanonicalizeNaNF* ins) {
auto output = ToFloatRegister(ins->output());
MOZ_ASSERT(output == ToFloatRegister(ins->input()));
- masm.canonicalizeFloatNaN(output);
+ masm.canonicalizeFloat(output);
}
template <size_t NumDefs>
diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h
@@ -869,34 +869,20 @@ void MacroAssembler::branchFloat32NotInUInt64Range(Address src, Register temp,
// ========================================================================
// Canonicalization primitives.
-void MacroAssembler::canonicalizeFloatNaN(FloatRegister reg) {
+void MacroAssembler::canonicalizeFloat(FloatRegister reg) {
Label notNaN;
branchFloat(DoubleOrdered, reg, reg, ¬NaN);
loadConstantFloat32(float(JS::GenericNaN()), reg);
bind(¬NaN);
}
-void MacroAssembler::canonicalizeDoubleNaN(FloatRegister reg) {
+void MacroAssembler::canonicalizeDouble(FloatRegister reg) {
Label notNaN;
branchDouble(DoubleOrdered, reg, reg, ¬NaN);
loadConstantDouble(JS::GenericNaN(), reg);
bind(¬NaN);
}
-void MacroAssembler::canonicalizeDoubleZero(FloatRegister reg,
- FloatRegister scratch) {
- // If denormals are disabled, then operations on them will flush denormal
- // values to zero (FTZ flag). We need the cheapest operation that is the
- // identity function.
- //
- // Unfortunately, just moving the float register doesn't trigger FTZ. Adding
- // '+-0' isn't an identity function, because it can toggle the sign bit.
- //
- // Therefore we choose to multiply by 1.0, which won't change the result.
- loadConstantDouble(1.0, scratch);
- mulDouble(scratch, reg);
-}
-
// ========================================================================
// Memory access primitives.
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
@@ -166,15 +166,15 @@ void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T& src,
break;
case Scalar::Float16:
loadFloat16(src, dest.fpu(), temp1, temp2, volatileLiveRegs);
- canonicalizeFloatNaN(dest.fpu());
+ canonicalizeFloat(dest.fpu());
break;
case Scalar::Float32:
loadFloat32(src, dest.fpu());
- canonicalizeFloatNaN(dest.fpu());
+ canonicalizeFloat(dest.fpu());
break;
case Scalar::Float64:
loadDouble(src, dest.fpu());
- canonicalizeDoubleNaN(dest.fpu());
+ canonicalizeDouble(dest.fpu());
break;
case Scalar::BigInt64:
case Scalar::BigUint64:
@@ -7467,7 +7467,8 @@ void MacroAssembler::branchValueConvertsToWasmAnyRefInline(
bind(&checkDouble);
{
unboxDouble(src, scratchFloat);
- convertDoubleToInt32(scratchFloat, scratchInt, &fallthrough);
+ convertDoubleToInt32(scratchFloat, scratchInt, &fallthrough,
+ /*negativeZeroCheck=*/false);
branch32(Assembler::GreaterThan, scratchInt,
Imm32(wasm::AnyRef::MaxI31Value), &fallthrough);
branch32(Assembler::LessThan, scratchInt, Imm32(wasm::AnyRef::MinI31Value),
@@ -7496,7 +7497,8 @@ void MacroAssembler::convertValueToWasmAnyRef(ValueOperand src, Register dest,
bind(&doubleValue);
{
unboxDouble(src, scratchFloat);
- convertDoubleToInt32(scratchFloat, dest, oolConvert);
+ convertDoubleToInt32(scratchFloat, dest, oolConvert,
+ /*negativeZeroCheck=*/false);
branch32(Assembler::GreaterThan, dest, Imm32(wasm::AnyRef::MaxI31Value),
oolConvert);
branch32(Assembler::LessThan, dest, Imm32(wasm::AnyRef::MinI31Value),
@@ -10753,7 +10755,7 @@ void MacroAssembler::touchFrameValues(Register numStackValues,
#ifdef FUZZING_JS_FUZZILLI
void MacroAssembler::fuzzilliHashDouble(FloatRegister src, Register result,
Register temp) {
- canonicalizeDoubleNaN(src);
+ canonicalizeDouble(src);
# ifdef JS_PUNBOX64
Register64 r64(temp);
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
@@ -2229,17 +2229,9 @@ class MacroAssembler : public MacroAssemblerSpecific {
// ========================================================================
// Canonicalization primitives.
- inline void canonicalizeDoubleNaN(FloatRegister reg);
+ inline void canonicalizeDouble(FloatRegister reg);
- inline void canonicalizeFloatNaN(FloatRegister reg);
-
- // If denormal support is disabled, there are 2^53 ways to represent zero.
- // This function canonicalizes the representation to either -0.0 or +0.0,
- // maintaining the sign bit of the input.
- //
- // This function will not change the value of the double if denormals are
- // enabled.
- inline void canonicalizeDoubleZero(FloatRegister reg, FloatRegister scratch);
+ inline void canonicalizeFloat(FloatRegister reg);
public:
// ========================================================================
diff --git a/js/src/wasm/WasmAnyRef.cpp b/js/src/wasm/WasmAnyRef.cpp
@@ -86,7 +86,7 @@ bool AnyRef::fromJSValue(JSContext* cx, HandleValue value,
if (value.isDouble()) {
double doubleValue = value.toDouble();
int32_t intValue;
- if (mozilla::NumberIsInt32(doubleValue, &intValue) &&
+ if (mozilla::NumberEqualsInt32(doubleValue, &intValue) &&
!int32NeedsBoxing(intValue)) {
result.set(AnyRef::fromInt32(intValue));
return true;
diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp
@@ -1111,37 +1111,6 @@ static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
case ValType::Ref: {
// Guarded against by temporarilyUnsupportedReftypeForEntry()
MOZ_RELEASE_ASSERT(funcType.args()[i].refType().isExtern());
-
- // If the value is a double that is a negative denormal and denormals
- // are disabled, then `branchValueConvertsToWasmAnyRefInline` will view
- // it as '-0' (which must be boxed in the OOL path). However, the
- // AnyRef boxing code uses `mozilla::NumberIsInt32` which does not
- // properly handle the CPU DAZ/FTZ flags and returns true and therefore
- // doesn't box the double. This leads to an assertion below where we
- // expected the value to be boxed.
- //
- // Making `mozilla::NumberIsInt32` handle the CPU DAZ/FTZ flags would
- // add a significant cost to many hot-paths. We instead just
- // eagerly canonicalize denormals to +-0.0 here to avoid inconsistent
- // results (see Bug 1971519).
- {
- ScratchDoubleScope tmpD(masm);
-
- Label notDouble;
- masm.branchTestDouble(Assembler::NotEqual, scratchV, ¬Double);
-
- // Unbox the double and canonicalize any denormal values
- masm.unboxDouble(scratchV, scratchF);
- masm.canonicalizeDoubleZero(scratchF, tmpD);
-
- // Box the value back into scratchV and also store it back to the
- // stack.
- masm.boxDouble(scratchF, scratchV, tmpD);
- masm.storeValue(scratchV, jitArgAddr);
-
- masm.bind(¬Double);
- }
-
masm.branchValueConvertsToWasmAnyRefInline(scratchV, scratchG, scratchF,
&next);
masm.jump(&oolCall);
@@ -1285,7 +1254,7 @@ static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
masm.boxNonDouble(JSVAL_TYPE_INT32, ReturnReg, JSReturnOperand);
break;
case ValType::F32: {
- masm.canonicalizeFloatNaN(ReturnFloat32Reg);
+ masm.canonicalizeFloat(ReturnFloat32Reg);
masm.convertFloat32ToDouble(ReturnFloat32Reg, ReturnDoubleReg);
GenPrintF64(DebugChannel::Function, masm, ReturnDoubleReg);
ScratchDoubleScope fpscratch(masm);
@@ -1293,7 +1262,7 @@ static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
break;
}
case ValType::F64: {
- masm.canonicalizeDoubleNaN(ReturnDoubleReg);
+ masm.canonicalizeDouble(ReturnDoubleReg);
GenPrintF64(DebugChannel::Function, masm, ReturnDoubleReg);
ScratchDoubleScope fpscratch(masm);
masm.boxDouble(ReturnDoubleReg, JSReturnOperand, fpscratch);
@@ -1587,11 +1556,11 @@ void wasm::GenerateDirectCallFromJit(MacroAssembler& masm, const FuncExport& fe,
GenPrintI64(DebugChannel::Function, masm, ReturnReg64);
break;
case wasm::ValType::F32:
- masm.canonicalizeFloatNaN(ReturnFloat32Reg);
+ masm.canonicalizeFloat(ReturnFloat32Reg);
GenPrintF32(DebugChannel::Function, masm, ReturnFloat32Reg);
break;
case wasm::ValType::F64:
- masm.canonicalizeDoubleNaN(ReturnDoubleReg);
+ masm.canonicalizeDouble(ReturnDoubleReg);
GenPrintF64(DebugChannel::Function, masm, ReturnDoubleReg);
break;
case wasm::ValType::Ref:
@@ -1825,14 +1794,14 @@ static void FillArgumentArrayForJitExit(MacroAssembler& masm, Register instance,
// Preserve the NaN pattern in the input.
ScratchDoubleScope fpscratch(masm);
masm.moveDouble(srcReg, fpscratch);
- masm.canonicalizeDoubleNaN(fpscratch);
+ masm.canonicalizeDouble(fpscratch);
GenPrintF64(DebugChannel::Import, masm, fpscratch);
masm.boxDouble(fpscratch, dst);
} else if (type == MIRType::Float32) {
// JS::Values can't store Float32, so convert to a Double.
ScratchDoubleScope fpscratch(masm);
masm.convertFloat32ToDouble(srcReg, fpscratch);
- masm.canonicalizeDoubleNaN(fpscratch);
+ masm.canonicalizeDouble(fpscratch);
GenPrintF64(DebugChannel::Import, masm, fpscratch);
masm.boxDouble(fpscratch, dst);
} else if (type == MIRType::Simd128) {
@@ -1875,7 +1844,7 @@ static void FillArgumentArrayForJitExit(MacroAssembler& masm, Register instance,
} else {
masm.loadDouble(src, dscratch);
}
- masm.canonicalizeDoubleNaN(dscratch);
+ masm.canonicalizeDouble(dscratch);
GenPrintF64(DebugChannel::Import, masm, dscratch);
masm.boxDouble(dscratch, dst);
} else if (type == MIRType::Simd128) {