Source code

Revision control

Copy as Markdown

Other Tools

// Check the integer fast path for the double remainder operator against
// results computed before anything is jitted.
// The two 32-bit halves are compared separately rather than combined into a
// double, which couldn't represent a 64-bit pattern exactly and would silently
// hide low-word differences. NaN is collapsed to a single token because neither
// its sign bit nor its payload is architecturally stable.
var f64 = new Float64Array(1);
var u32 = new Uint32Array(f64.buffer);
function bits(x) {
if (Number.isNaN(x)) {
return "NaN";
}
f64[0] = x;
return `${(u32[1] >>> 0).toString(16)}:${(u32[0] >>> 0).toString(16)}`;
}
var values = [
0, -0, 1, -1, 2, -2, 3, -3, 0.5, -0.5, 2.5, -2.5,
1e7, -1e7, 12345678, -12345678,
2147483647, -2147483648, -2147483649, // INT32_MAX, INT32_MIN, INT32_MIN - 1
4294967296, -4294967296, // 2^32, -2^32
9007199254740991, -9007199254740991, // +/- (2^53 - 1), largest exact odd int
9007199254740992, 9007199254740994, // 2^53 and 2^53 + 2 (2^53 + 1 isn't exact)
12345678901234, -12345678901234,
9223372036854775808, -9223372036854775808, // 2^63 and -2^63 (INT64_MIN)
9223372036854774784, -9223372036854774784, // largest double below 2^63
1e19, -1e19, 1e30, -1e30,
Infinity, -Infinity, NaN, Number.MIN_VALUE, Number.MAX_VALUE,
];
function mod(a, b) {
return a % b;
}
// Constant divisors are lowered differently from variable ones, so exercise a
// handful of interesting ones. Each has its own function with a literal
// divisor (so the constant is visible to the JIT at the call site) and is
// checked on its own rather than folded together, so a mismatch points
// straight at the divisor that broke.
function modConst2p5(x) { return x % 2.5; } // non-integer divisor
function modConst1e7(x) { return x % 1e7; } // integer divisor
function modConst0(x) { return x % 0; } // NaN result
function modConstM1(x) { return x % -1; } // rejected -1 divisor
function modConstM0(x) { return x % -0; } // -0 divisor, same as % 0
function modConst3(x) { return x % 3; } // small integer divisor
function modConst1e30(x) { return x % 1e30; } // out-of-range integer divisor
function modConstNaN(x) { return x % NaN; } // NaN divisor
function modConstInf(x) { return x % Infinity; } // Infinity divisor
// Names are only used to make an assertion failure identify the divisor.
var constMods = [
["% 2.5", modConst2p5], ["% 1e7", modConst1e7], ["% 0", modConst0],
["% -1", modConstM1], ["% -0", modConstM0], ["% 3", modConst3],
["% 1e30", modConst1e30], ["% NaN", modConstNaN], ["% Infinity", modConstInf],
];
var expected = [];
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values.length; j++) {
expected.push(bits(values[i] % values[j]));
}
for (var c = 0; c < constMods.length; c++) {
expected.push(bits(constMods[c][1](values[i])));
}
}
for (var iter = 0; iter < 60; iter++) {
var k = 0;
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values.length; j++) {
assertEq(bits(mod(values[i], values[j])), expected[k++],
`${values[i]} % ${values[j]}`);
}
for (var c = 0; c < constMods.length; c++) {
assertEq(bits(constMods[c][1](values[i])), expected[k++],
`${values[i]} ${constMods[c][0]}`);
}
}
}