Bug 1531269 - Fix bugs in BigInt.asUintN r=jwalden,terpri
authorAndy Wingo <wingo@igalia.com>
Fri, 15 Mar 2019 14:33:26 +0000
changeset 522054 8743fe149037c18e2d17e455833ce22112c5317a
parent 522053 189c2c75a5ae920f1caf8c631415b3d282f66c60
child 522055 cfa5566d93a89cef51c2330b11743c8163a46d48
push id10871
push usercbrindusan@mozilla.com
push dateMon, 18 Mar 2019 15:49:32 +0000
treeherdermozilla-beta@018abdd16060 [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;
   }