[Corelib, VM runtime] Fix handling of zero operand in Bigint operations (fixes #32465).

Fix VM, dart2js, and dcc Bigint implementations.
Add shift tests.
Re-enable Bigint intrinsics on VM.

Change-Id: Iec19eac8069cf17783a5346289ea2745ffcc7c26
Reviewed-on: https://dart-review.googlesource.com/46570
Reviewed-by: Florian Loitsch <floitsch@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Régis Crelier 2018-03-21 21:44:10 +00:00
parent 9f0e391e28
commit f2806ab624
5 changed files with 99 additions and 16 deletions

View file

@ -1219,6 +1219,7 @@ class _BigIntImpl implements BigInt {
/// Does *not* clear digits below ds.
static void _lsh(
Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
assert(xUsed > 0);
final digitShift = n ~/ _digitBits;
final bitShift = n % _digitBits;
final carryBitShift = _digitBits - bitShift;
@ -1248,6 +1249,7 @@ class _BigIntImpl implements BigInt {
if (shiftAmount < 0) {
throw new ArgumentError("shift-amount must be posititve $shiftAmount");
}
if (_isZero) return this;
final digitShift = shiftAmount ~/ _digitBits;
final bitShift = shiftAmount % _digitBits;
if (bitShift == 0) {
@ -1283,6 +1285,7 @@ class _BigIntImpl implements BigInt {
// resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] >> n.
static void _rsh(
Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
assert(xUsed > 0);
final digitsShift = n ~/ _digitBits;
final bitShift = n % _digitBits;
final carryBitShift = _digitBits - bitShift;
@ -1310,6 +1313,7 @@ class _BigIntImpl implements BigInt {
if (shiftAmount < 0) {
throw new ArgumentError("shift-amount must be posititve $shiftAmount");
}
if (_isZero) return this;
final digitShift = shiftAmount ~/ _digitBits;
final bitShift = shiftAmount % _digitBits;
if (bitShift == 0) {
@ -1552,6 +1556,7 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator &(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero || other._isZero) return zero;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) & (-other) == ~(this-1) & ~(other-1)
@ -1591,6 +1596,8 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator |(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) | (-other) == ~(this-1) | ~(other-1)
@ -1631,6 +1638,8 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator ^(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) ^ (-other) == ~(this-1) ^ ~(other-1) == (this-1) ^ (other-1)
@ -1665,6 +1674,7 @@ class _BigIntImpl implements BigInt {
* This maps any integer `x` to `-x - 1`.
*/
_BigIntImpl operator ~() {
if (_isZero) return _minusOne;
if (_isNegative) {
// ~(-this) == ~(~(this-1)) == this-1
return _absSubSetSign(one, false);
@ -1677,6 +1687,8 @@ class _BigIntImpl implements BigInt {
/// Addition operator.
_BigIntImpl operator +(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
var isNegative = _isNegative;
if (isNegative == other._isNegative) {
// this + other == this + other
@ -1694,6 +1706,8 @@ class _BigIntImpl implements BigInt {
/// Subtraction operator.
_BigIntImpl operator -(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return -other;
if (other._isZero) return this;
var isNegative = _isNegative;
if (isNegative != other._isNegative) {
// this - (-other) == this + other

View file

@ -540,6 +540,7 @@ class _BigIntImpl implements BigInt {
/// Note: This function may be intrinsified.
static void _lsh(
Uint32List xDigits, int xUsed, int n, Uint32List resultDigits) {
assert(xUsed > 0);
final digitShift = n ~/ _digitBits;
final bitShift = n % _digitBits;
final carryBitShift = _digitBits - bitShift;
@ -569,6 +570,7 @@ class _BigIntImpl implements BigInt {
if (shiftAmount < 0) {
throw new ArgumentError("shift-amount must be positive $shiftAmount");
}
if (_isZero) return this;
final digitShift = shiftAmount ~/ _digitBits;
final bitShift = shiftAmount % _digitBits;
if (bitShift == 0) {
@ -611,6 +613,7 @@ class _BigIntImpl implements BigInt {
/// Note: This function may be intrinsified.
static void _rsh(
Uint32List xDigits, int xUsed, int n, Uint32List resultDigits) {
assert(xUsed > 0);
final digitsShift = n ~/ _digitBits;
final bitShift = n % _digitBits;
final carryBitShift = _digitBits - bitShift;
@ -638,6 +641,7 @@ class _BigIntImpl implements BigInt {
if (shiftAmount < 0) {
throw new ArgumentError("shift-amount must be positive $shiftAmount");
}
if (_isZero) return this;
final digitShift = shiftAmount ~/ _digitBits;
final bitShift = shiftAmount % _digitBits;
if (bitShift == 0) {
@ -902,6 +906,7 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator &(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero || other._isZero) return zero;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) & (-other) == ~(this-1) & ~(other-1)
@ -941,6 +946,8 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator |(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) | (-other) == ~(this-1) | ~(other-1)
@ -981,6 +988,8 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator ^(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) ^ (-other) == ~(this-1) ^ ~(other-1) == (this-1) ^ (other-1)
@ -1015,6 +1024,7 @@ class _BigIntImpl implements BigInt {
* This maps any integer `x` to `-x - 1`.
*/
_BigIntImpl operator ~() {
if (_isZero) return _minusOne;
if (_isNegative) {
// ~(-this) == ~(~(this-1)) == this-1
return _absSubSetSign(one, false);
@ -1027,6 +1037,8 @@ class _BigIntImpl implements BigInt {
/// Addition operator.
_BigIntImpl operator +(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
var isNegative = _isNegative;
if (isNegative == other._isNegative) {
// this + other == this + other
@ -1044,6 +1056,8 @@ class _BigIntImpl implements BigInt {
/// Subtraction operator.
_BigIntImpl operator -(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return -other;
if (other._isZero) return this;
var isNegative = _isNegative;
if (isNegative != other._isNegative) {
// this - (-other) == this + other

View file

@ -146,14 +146,15 @@ namespace dart {
V(_Smi, ~, Smi_bitNegate, Smi, 0x67299f4f) \
V(_Smi, get:bitLength, Smi_bitLength, Smi, 0x25b3cb0a) \
V(_Smi, _bitAndFromSmi, Smi_bitAndFromSmi, Smi, 0x562d5047) \
V(_Bigint, _lsh, Bigint_lsh, Dynamic, 0x7b99f80e) \
V(_Bigint, _rsh, Bigint_rsh, Dynamic, 0x5262b3a1) \
V(_Bigint, _absAdd, Bigint_absAdd, Dynamic, 0x07cad968) \
V(_Bigint, _absSub, Bigint_absSub, Dynamic, 0x1bf1bb4c) \
V(_Bigint, _mulAdd, Bigint_mulAdd, Dynamic, 0x229759b7) \
V(_Bigint, _sqrAdd, Bigint_sqrAdd, Dynamic, 0x5212b81f) \
V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, Dynamic, 0x4dd342fe) \
V(_Montgomery, _mulMod, Montgomery_mulMod, Dynamic, 0x17a515ac) \
V(_BigIntImpl, _lsh, Bigint_lsh, Dynamic, 0x5b6cfc8b) \
V(_BigIntImpl, _rsh, Bigint_rsh, Dynamic, 0x6ff14a49) \
V(_BigIntImpl, _absAdd, Bigint_absAdd, Dynamic, 0x5bf14238) \
V(_BigIntImpl, _absSub, Bigint_absSub, Dynamic, 0x1de5bd32) \
V(_BigIntImpl, _mulAdd, Bigint_mulAdd, Smi, 0x6f277966) \
V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, Smi, 0x68e4c8ea) \
V(_BigIntImpl, _estimateQuotientDigit, Bigint_estQuotientDigit, Smi, \
0x35456d91) \
V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, Smi, 0x0f7b0375) \
V(_Double, >, Double_greaterThan, Bool, 0x4f1375a3) \
V(_Double, >=, Double_greaterEqualThan, Bool, 0x4260c184) \
V(_Double, <, Double_lessThan, Bool, 0x365d1eba) \
@ -460,14 +461,14 @@ namespace dart {
V(::, sin, MathSin, 0x6b7bd98c) \
V(::, sqrt, MathSqrt, 0x70482cf3) \
V(::, tan, MathTan, 0x3bcd772a) \
V(_Bigint, _lsh, Bigint_lsh, 0x7b99f80e) \
V(_Bigint, _rsh, Bigint_rsh, 0x5262b3a1) \
V(_Bigint, _absAdd, Bigint_absAdd, 0x07cad968) \
V(_Bigint, _absSub, Bigint_absSub, 0x1bf1bb4c) \
V(_Bigint, _mulAdd, Bigint_mulAdd, 0x229759b7) \
V(_Bigint, _sqrAdd, Bigint_sqrAdd, 0x5212b81f) \
V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 0x4dd342fe) \
V(_Montgomery, _mulMod, Montgomery_mulMod, 0x17a515ac) \
V(_BigIntImpl, _lsh, Bigint_lsh, 0x5b6cfc8b) \
V(_BigIntImpl, _rsh, Bigint_rsh, 0x6ff14a49) \
V(_BigIntImpl, _absAdd, Bigint_absAdd, 0x5bf14238) \
V(_BigIntImpl, _absSub, Bigint_absSub, 0x1de5bd32) \
V(_BigIntImpl, _mulAdd, Bigint_mulAdd, 0x6f277966) \
V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, 0x68e4c8ea) \
V(_BigIntImpl, _estimateQuotientDigit, Bigint_estQuotientDigit, 0x35456d91) \
V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, 0x0f7b0375) \
V(_Double, >, Double_greaterThan, 0x4f1375a3) \
V(_Double, >=, Double_greaterEqualThan, 0x4260c184) \
V(_Double, <, Double_lessThan, 0x365d1eba) \

View file

@ -1299,6 +1299,7 @@ class _BigIntImpl implements BigInt {
/// Does *not* clear digits below ds.
static void _lsh(
Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
assert(xUsed > 0);
final digitShift = n ~/ _digitBits;
final bitShift = n % _digitBits;
final carryBitShift = _digitBits - bitShift;
@ -1328,6 +1329,7 @@ class _BigIntImpl implements BigInt {
if (shiftAmount < 0) {
throw new ArgumentError("shift-amount must be posititve $shiftAmount");
}
if (_isZero) return this;
final digitShift = shiftAmount ~/ _digitBits;
final bitShift = shiftAmount % _digitBits;
if (bitShift == 0) {
@ -1363,6 +1365,7 @@ class _BigIntImpl implements BigInt {
// resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] >> n.
static void _rsh(
Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
assert(xUsed > 0);
final digitsShift = n ~/ _digitBits;
final bitShift = n % _digitBits;
final carryBitShift = _digitBits - bitShift;
@ -1390,6 +1393,7 @@ class _BigIntImpl implements BigInt {
if (shiftAmount < 0) {
throw new ArgumentError("shift-amount must be posititve $shiftAmount");
}
if (_isZero) return this;
final digitShift = shiftAmount ~/ _digitBits;
final bitShift = shiftAmount % _digitBits;
if (bitShift == 0) {
@ -1632,6 +1636,7 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator &(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero || other._isZero) return zero;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) & (-other) == ~(this-1) & ~(other-1)
@ -1671,6 +1676,8 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator |(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) | (-other) == ~(this-1) | ~(other-1)
@ -1711,6 +1718,8 @@ class _BigIntImpl implements BigInt {
*/
_BigIntImpl operator ^(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
if (_isNegative == other._isNegative) {
if (_isNegative) {
// (-this) ^ (-other) == ~(this-1) ^ ~(other-1) == (this-1) ^ (other-1)
@ -1745,6 +1754,7 @@ class _BigIntImpl implements BigInt {
* This maps any integer `x` to `-x - 1`.
*/
_BigIntImpl operator ~() {
if (_isZero) return _minusOne;
if (_isNegative) {
// ~(-this) == ~(~(this-1)) == this-1
return _absSubSetSign(one, false);
@ -1757,6 +1767,8 @@ class _BigIntImpl implements BigInt {
/// Addition operator.
_BigIntImpl operator +(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return other;
if (other._isZero) return this;
var isNegative = _isNegative;
if (isNegative == other._isNegative) {
// this + other == this + other
@ -1774,6 +1786,8 @@ class _BigIntImpl implements BigInt {
/// Subtraction operator.
_BigIntImpl operator -(BigInt bigInt) {
_BigIntImpl other = bigInt;
if (_isZero) return -other;
if (other._isZero) return this;
var isNegative = _isNegative;
if (isNegative != other._isNegative) {
// this - (-other) == this + other

View file

@ -280,6 +280,33 @@ testSmiOverflow() {
Expect.equals(-BigInt.parse("1000000001000000000"), a * b);
}
testBigintAnd() {
var a = BigInt.parse("0x55555555555555555555");
var b = BigInt.parse("0x33333333333333333333");
var c = BigInt.parse("0x11111111111111111111");
Expect.equals(BigInt.zero, BigInt.zero & a);
Expect.equals(BigInt.zero, a & BigInt.zero);
Expect.equals(c, a & b);
}
testBigintOr() {
var a = BigInt.parse("0x33333333333333333333");
var b = BigInt.parse("0x55555555555555555555");
var c = BigInt.parse("0x77777777777777777777");
Expect.equals(a, BigInt.zero | a);
Expect.equals(a, a | BigInt.zero);
Expect.equals(c, a | b);
}
testBigintXor() {
var a = BigInt.parse("0x33333333333333333333");
var b = BigInt.parse("0x55555555555555555555");
var c = BigInt.parse("0x66666666666666666666");
Expect.equals(a, BigInt.zero ^ a);
Expect.equals(a, a ^ BigInt.zero);
Expect.equals(c, a ^ b);
}
testBigintAdd() {
// Bigint and Smi.
var a = BigInt.parse("12345678901234567890");
@ -289,6 +316,8 @@ testBigintAdd() {
// Bigint and Bigint.
a = BigInt.parse("10000000000000000001");
Expect.equals(BigInt.parse("20000000000000000002"), a + a);
Expect.equals(a, BigInt.zero + a);
Expect.equals(a, a + BigInt.zero);
}
testBigintSub() {
@ -300,6 +329,8 @@ testBigintSub() {
// Bigint and Bigint.
a = BigInt.parse("10000000000000000001");
Expect.equals(BigInt.parse("20000000000000000002"), a + a);
Expect.equals(-a, BigInt.zero - a);
Expect.equals(a, a - BigInt.zero);
}
testBigintMul() {
@ -634,6 +665,12 @@ testBigintNegate() {
}
testShiftAmount() {
Expect.equals(BigInt.zero, BigInt.zero << 0);
Expect.equals(BigInt.zero, BigInt.zero >> 0);
Expect.equals(BigInt.zero, BigInt.zero << 1234567890);
Expect.equals(BigInt.zero, BigInt.zero >> 1234567890);
Expect.equals(BigInt.two.pow(999), BigInt.one << 999);
Expect.equals(BigInt.one, BigInt.two.pow(999) >> 999);
Expect.equals(BigInt.zero, new BigInt.from(12) >> 0x7FFFFFFFFFFFFFFF);
Expect.equals(-BigInt.one, -new BigInt.from(12) >> 0x7FFFFFFFFFFFFFFF);
bool exceptionCaught = false;
@ -910,6 +947,9 @@ main() {
testModInverse();
testGcd();
testSmiOverflow();
testBigintAnd();
testBigintOr();
testBigintXor();
testBigintAdd();
testBigintSub();
testBigintMul();