Bug 1415772: Implement MNearbyInt recover instruction
MozReview-Commit-ID: D7JdEHjDl2W
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -490,25 +490,43 @@ function rfloor_object(i) {
var x = Math.floor(o);
t = 1000.1111;
if (uceFault_floor_object(i) || uceFault_floor_object(i))
assertEq(x, i);
assertRecoveredOnBailout(x, false);
return i;
}
+let uceFault_floor_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_floor_double'));
+function rfloor_double(i) {
+ const x = Math.floor(i + (-1 >>> 0));
+ if (uceFault_floor_double(i) || uceFault_floor_double(i))
+ assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
+ assertRecoveredOnBailout(x, true);
+ return i;
+}
+
var uceFault_ceil_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_ceil_number'));
function rceil_number(i) {
var x = Math.ceil(-i - 0.12010799100);
if (uceFault_ceil_number(i) || uceFault_ceil_number(i))
assertEq(x, -i);
assertRecoveredOnBailout(x, true);
return i;
}
+let uceFault_ceil_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_ceil_double'));
+function rceil_double(i) {
+ const x = Math.floor(i + (-1 >>> 0));
+ if (uceFault_ceil_double(i) || uceFault_ceil_double(i))
+ assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
+ assertRecoveredOnBailout(x, true);
+ return i;
+}
+
var uceFault_round_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_round'));
function rround_number(i) {
var x = Math.round(i + 1.4);
if (uceFault_round_number(i) || uceFault_round_number(i))
assertEq(x, 100); /* = i + 1*/
assertRecoveredOnBailout(x, true);
return i;
}
@@ -1386,18 +1404,20 @@ for (j = 100 - max; j < 100; j++) {
rconcat_string(i);
rconcat_number(i);
rstring_length(i);
rarguments_length_1(i);
rarguments_length_3(i, 0, 1);
rinline_arguments_length_1(i);
rinline_arguments_length_3(i, 0, 1);
rfloor_number(i);
+ rfloor_double(i);
rfloor_object(i);
rceil_number(i);
+ rceil_double(i);
rround_number(i);
rround_double(i);
rcharCodeAt(i);
rfrom_char_code(i);
rfrom_char_code_non_ascii(i);
rpow_number(i);
rpow_object(i);
rpowhalf_number(i);
--- a/js/src/jit-test/tests/ion/rinstructions-no-sse4.js
+++ b/js/src/jit-test/tests/ion/rinstructions-no-sse4.js
@@ -13,25 +13,38 @@ const max = 200;
// of uceFault, and ensure that the bailout is correct when uceFault
// is replaced (which cause an invalidation bailout)
let uceFault = function (i) {
if (i > 98)
uceFault = function (i) { return true; };
return false;
};
+let uceFault_ceil_double = eval(
+ uneval(uceFault)
+ .replace('uceFault', 'uceFault_ceil_double')
+);
+function rceil_double(i) {
+ const x = Math.ceil(i + (-1 >>> 0));
+ if (uceFault_ceil_double(i) || uceFault_ceil_double(i))
+ assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
+ assertRecoveredOnBailout(x, true);
+ return i;
+}
+
let uceFault_floor_double = eval(
uneval(uceFault)
.replace('uceFault', 'uceFault_floor_double')
);
function rfloor_double(i) {
const x = Math.floor(i + (-1 >>> 0));
if (uceFault_floor_double(i) || uceFault_floor_double(i))
assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
assertRecoveredOnBailout(x, true);
return i;
}
for (let j = 100 - max; j < 100; j++) {
with({}){} // Do not Ion-compile this loop.
const i = j < 2 ? (Math.abs(j) % 50) + 2 : j;
+ rceil_double(i);
rfloor_double(i);
}
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -7012,16 +7012,17 @@ class MMathFunction
void computeRange(TempAllocator& alloc) override;
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
if (input()->type() == MIRType::SinCosDouble)
return false;
switch(function_) {
case Sin:
case Log:
+ case Ceil:
case Floor:
case Round:
return true;
default:
return false;
}
}
@@ -12618,16 +12619,28 @@ class MNearbyInt
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins) &&
ins->toNearbyInt()->roundingMode() == roundingMode_;
}
void printOpcode(GenericPrinter& out) const override;
+ MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+
+ bool canRecoverOnBailout() const override {
+ switch (roundingMode_) {
+ case RoundingMode::Up:
+ case RoundingMode::Down:
+ return true;
+ default:
+ return false;
+ }
+ }
+
ALLOW_CLONE(MNearbyInt)
};
class MGetIteratorCache
: public MUnaryInstruction,
public BoxExceptPolicy<0, MIRType::Object>::Data
{
explicit MGetIteratorCache(MDefinition* val)
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -953,20 +953,50 @@ RHypot::recover(JSContext* cx, SnapshotI
if(!js::math_hypot_handle(cx, vec, &result))
return false;
iter.storeInstructionResult(result);
return true;
}
bool
+MNearbyInt::writeRecoverData(CompactBufferWriter& writer) const
+{
+ MOZ_ASSERT(canRecoverOnBailout());
+ switch (roundingMode_) {
+ case RoundingMode::Up:
+ writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
+ return true;
+ case RoundingMode::Down:
+ writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
+ return true;
+ default:
+ MOZ_CRASH("Unsupported rounding mode.");
+ }
+}
+
+RNearbyInt::RNearbyInt(CompactBufferReader& reader)
+{
+ roundingMode_ = reader.readByte();
+}
+
+bool
+RNearbyInt::recover(JSContext* cx, SnapshotIterator& iter) const
+{
+ MOZ_CRASH("Unsupported rounding mode.");
+}
+
+bool
MMathFunction::writeRecoverData(CompactBufferWriter& writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
switch (function_) {
+ case Ceil:
+ writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
+ return true;
case Floor:
writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
return true;
case Round:
writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
return true;
case Sin:
case Log:
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -82,16 +82,17 @@ namespace jit {
_(FromCharCode) \
_(Pow) \
_(PowHalf) \
_(MinMax) \
_(Abs) \
_(Sqrt) \
_(Atan2) \
_(Hypot) \
+ _(NearbyInt) \
_(MathFunction) \
_(Random) \
_(StringSplit) \
_(NaNToZero) \
_(RegExpMatcher) \
_(RegExpSearcher) \
_(RegExpTester) \
_(StringReplace) \
@@ -461,16 +462,27 @@ class RHypot final : public RInstruction
uint32_t numOperands() const override {
return numOperands_;
}
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
};
+class RNearbyInt final : public RInstruction
+{
+ private:
+ uint8_t roundingMode_;
+
+ public:
+ RINSTRUCTION_HEADER_NUM_OP_(NearbyInt, 1)
+
+ MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
+};
+
class RMathFunction final : public RInstruction
{
private:
uint8_t function_;
public:
RINSTRUCTION_HEADER_NUM_OP_(MathFunction, 1)