Skip to content

Commit

Permalink
Fix bigint side effects for >>>, /, %
Browse files Browse the repository at this point in the history
Summary:
BigInt differs from numbers - several bigint operations can throw an
exception, specifically:
- >>> is not allowed at all and throws
- / and % can result in division by zero

Improve the side effect model and add a test.

Reported in #1212

Reviewed By: avp

Differential Revision: D52013220

fbshipit-source-id: 34606cb7d53a3db3ea49dd026661b7fd340583e5
  • Loading branch information
Tzvetan Mikov authored and facebook-github-bot committed Dec 15, 2023
1 parent 40748fa commit 39d60e6
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
21 changes: 18 additions & 3 deletions lib/IR/Instrs.cpp
Expand Up @@ -26,6 +26,7 @@ unsigned TerminatorInst::getNumSuccessors() const {
return I->getNumSuccessorsImpl();
#define BEGIN_TERMINATOR(NAME, PARENT) TERMINATOR(NAME, PARENT)
#include "hermes/IR/Instrs.def"

llvm_unreachable("not a terminator?!");
}

Expand All @@ -36,6 +37,7 @@ BasicBlock *TerminatorInst::getSuccessor(unsigned idx) const {
return I->getSuccessorImpl(idx);
#define BEGIN_TERMINATOR(NAME, PARENT) TERMINATOR(NAME, PARENT)
#include "hermes/IR/Instrs.def"

llvm_unreachable("not a terminator?!");
}

Expand All @@ -46,6 +48,7 @@ void TerminatorInst::setSuccessor(unsigned idx, BasicBlock *B) {
return I->setSuccessorImpl(idx, B);
#define BEGIN_TERMINATOR(NAME, PARENT) TERMINATOR(NAME, PARENT)
#include "hermes/IR/Instrs.def"

llvm_unreachable("not a terminator?!");
}

Expand Down Expand Up @@ -134,6 +137,21 @@ SideEffect BinaryOperatorInst::getBinarySideEffect(
return SideEffect{}.setIdempotent();
break;

case ValueKind::BinaryUnsignedRightShiftInstKind:
case ValueKind::BinaryDivideInstKind:
case ValueKind::BinaryModuloInstKind:
// We can only reason about primitive types.
if (!leftTy.isPrimitive() || !rightTy.isPrimitive())
break;
// if either of the operands can be a BigInt, this instruction may throw
// for one of the following reasons:
// - BigInt doesn't have unsigned right shift.
// - BigInt division by zero.
if (leftTy.canBeBigInt() || rightTy.canBeBigInt())
return SideEffect{}.setThrow();
// We have primitive operands that are not BigInt.
return SideEffect{}.setIdempotent();

case ValueKind::BinaryAddInstKind:
// We can only reason about primitive types.
if (!leftTy.isPrimitive() || !rightTy.isPrimitive())
Expand All @@ -145,11 +163,8 @@ SideEffect BinaryOperatorInst::getBinarySideEffect(

case ValueKind::BinaryLeftShiftInstKind:
case ValueKind::BinaryRightShiftInstKind:
case ValueKind::BinaryUnsignedRightShiftInstKind:
case ValueKind::BinarySubtractInstKind:
case ValueKind::BinaryMultiplyInstKind:
case ValueKind::BinaryDivideInstKind:
case ValueKind::BinaryModuloInstKind:
case ValueKind::BinaryOrInstKind:
case ValueKind::BinaryXorInstKind:
case ValueKind::BinaryAndInstKind:
Expand Down
29 changes: 27 additions & 2 deletions test/shermes/regress-bigint-dce.js
Expand Up @@ -8,11 +8,12 @@
// RUN: %shermes -exec -O0 %s | %FileCheck --match-full-lines %s
// RUN: %shermes -exec -O %s | %FileCheck --match-full-lines %s

(function() {

// Verify that arithmetic operations with a BigInt operand and non-BigInt
// operand (except adds) are not DCE-d, because that would throw a runtime
// exception.

(function() {
try {
1n + 1;
} catch (e) {
Expand All @@ -25,5 +26,29 @@ try {
} catch (e) {
print(e);
}
})();
//CHECK-NEXT: TypeError: Cannot convert BigInt to number

// Verify that BigInt operations that may throw are not eliminated:
// unsigned right shift, division, modulo.
try {
1n >>> 1n;
} catch (e) {
print(e);
}
//CHECK-NEXT: TypeError: BigInts have no unsigned shift

try {
1n / 0n;
} catch (e) {
print(e);
}
//CHECK-NEXT: RangeError: Division by zero

try {
1n % 0n;
} catch (e) {
print(e);
}
//CHECK-NEXT: RangeError: Division by zero

})();

0 comments on commit 39d60e6

Please sign in to comment.