Bug 1531269 - Fix bugs in BigInt.asUintN r=jwalden,terpri
authorAndy Wingo <wingo@igalia.com>
Fri, 15 Mar 2019 14:33:26 +0000
changeset 464391 8743fe149037
parent 464390 189c2c75a5ae
child 464392 cfa5566d93a8
push id35716
push useraciure@mozilla.com
push dateSun, 17 Mar 2019 09:42:17 +0000
treeherdermozilla-central@8ee97c045359 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden, terpri
bugs1531269
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1531269 - Fix bugs in BigInt.asUintN r=jwalden,terpri Differential Revision: https://phabricator.services.mozilla.com/D21505
js/src/jit-test/tests/bigint/bug1531269.js
js/src/vm/BigIntType.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/bigint/bug1531269.js
@@ -0,0 +1,13 @@
+var x = 0b1111n << 126n;
+// octets:     g f e d c b a 9 8 7 6 5 4 3 2 1 0
+assertEq(x, 0x03c0000000000000000000000000000000n);
+
+function tr(bits, x) { return BigInt.asUintN(bits, x); }
+
+// octets:              g f e d c b a 9 8 7 6 5 4 3 2 1 0
+assertEq(tr(131, x), 0x03c0000000000000000000000000000000n);
+assertEq(tr(130, x), 0x03c0000000000000000000000000000000n);
+assertEq(tr(129, x), 0x01c0000000000000000000000000000000n);
+assertEq(tr(128, x), 0x00c0000000000000000000000000000000n);
+assertEq(tr(127, x), 0x0040000000000000000000000000000000n);
+assertEq(tr(126, x), 0n);
--- a/js/src/vm/BigIntType.cpp
+++ b/js/src/vm/BigIntType.cpp
@@ -1577,16 +1577,17 @@ BigInt* BigInt::createFromDouble(JSConte
     int remainingMantissaBits = mantissaTopBit - msdTopBit;
     digit = mantissa >> remainingMantissaBits;
     mantissa = mantissa << (64 - remainingMantissaBits);
   } else {
     MOZ_ASSERT(msdTopBit >= mantissaTopBit);
     digit = mantissa << (msdTopBit - mantissaTopBit);
     mantissa = 0;
   }
+  MOZ_ASSERT(digit != 0, "most significant digit should not be zero");
   result->setDigit(--length, digit);
 
   // Fill in digits containing mantissa contributions.
   while (mantissa) {
     MOZ_ASSERT(length > 0,
                "double bits were all non-fractional, so there must be "
                "digits present to hold them");
 
@@ -2285,17 +2286,17 @@ BigInt* BigInt::truncateAndSubFromPowerO
     resultMSD = digitSub(resultMSD, borrow, &newBorrow);
     MOZ_ASSERT(newBorrow == 0, "result < 2^bits");
     // If all subtracted bits were zero, we have to get rid of the
     // materialized minuendMSD again.
     resultMSD &= (minuendMSD - 1);
   }
   result->setDigit(resultLength - 1, resultMSD);
 
-  return trimHighZeroDigits(cx, result);
+  return destructivelyTrimHighZeroDigits(cx, result);
 }
 
 BigInt* BigInt::asUintN(JSContext* cx, HandleBigInt x, uint64_t bits) {
   if (x->isZero()) {
     return x;
   }
 
   if (bits == 0) {
@@ -2322,31 +2323,43 @@ BigInt* BigInt::asUintN(JSContext* cx, H
   size_t msdBits = DigitBits - DigitLeadingZeroes(msd);
   size_t bitLength = msdBits + (x->digitLength() - 1) * DigitBits;
 
   if (bits >= bitLength) {
     return x;
   }
 
   size_t length = CeilDiv(bits, DigitBits);
-  bool isNegative = false;
-
+  MOZ_ASSERT(length >= 2, "single-digit cases should be handled above");
+  MOZ_ASSERT(length <= x->digitLength());
+
+  // Eagerly trim high zero digits.
+  const size_t highDigitBits = ((bits - 1) % DigitBits) + 1;
+  const Digit highDigitMask = Digit(-1) >> (DigitBits - highDigitBits);
+  Digit mask = highDigitMask;
+  while (length > 0) {
+    if (x->digit(length - 1) & mask) {
+      break;
+    }
+
+    mask = Digit(-1);
+    length--;
+  }
+
+  const bool isNegative = false;
   BigInt* res = createUninitialized(cx, length, isNegative);
-  if (!res) {
+  if (res == nullptr) {
     return nullptr;
   }
-
-  MOZ_ASSERT(length >= 2, "single-digit cases should be handled above");
-  MOZ_ASSERT(length <= x->digitLength());
-  for (size_t i = 0; i < length - 1; i++) {
-    res->setDigit(i, x->digit(i));
+  
+  while (length-- > 0) {
+    res->setDigit(length, x->digit(length) & mask);
+    mask = Digit(-1);
   }
-
-  Digit mask = Digit(-1) >> (DigitBits - (bits % DigitBits));
-  res->setDigit(length - 1, x->digit(length - 1) & mask);
+  MOZ_ASSERT_IF(length == 0, res->isZero());
 
   return res;
 }
 
 BigInt* BigInt::asIntN(JSContext* cx, HandleBigInt x, uint64_t bits) {
   if (x->isZero()) {
     return x;
   }