summaryrefslogtreecommitdiff
path: root/js/src/vm
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2023-07-25 01:59:56 -0500
committerBrian Smith <brian@dbsoft.org>2023-07-25 01:59:56 -0500
commit7a5b68c98ebde399166bef6fecb932760dc1006d (patch)
tree8c691876984e1a31bec40fb1d3a5f1853476d107 /js/src/vm
parent1edc4e41d3d4fd1f3bd9886cba0c0e38b24c194b (diff)
downloaduxp-7a5b68c98ebde399166bef6fecb932760dc1006d.tar.gz
Issue #2026 - Part 2b - Format BigInts representable as int64_t without first converting them to strings.
https://bugzilla.mozilla.org/show_bug.cgi?id=1543677
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/BigIntType.cpp40
-rw-r--r--js/src/vm/BigIntType.h5
2 files changed, 44 insertions, 1 deletions
diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp
index 44bb1923f7..8382c641fa 100644
--- a/js/src/vm/BigIntType.cpp
+++ b/js/src/vm/BigIntType.cpp
@@ -87,6 +87,7 @@
#include "mozilla/WrappingOperations.h"
#include <functional>
+#include <limits>
#include <math.h>
#include <memory>
@@ -2211,6 +2212,43 @@ uint64_t BigInt::toUint64(BigInt* x) {
return digit;
}
+bool BigInt::isInt64(BigInt* x, int64_t* result) {
+ MOZ_MAKE_MEM_UNDEFINED(result, sizeof(*result));
+
+ size_t length = x->digitLength();
+ if (length > (DigitBits == 32 ? 2 : 1)) {
+ return false;
+ }
+
+ if (length == 0) {
+ *result = 0;
+ return true;
+ }
+
+ uint64_t magnitude = x->digit(0);
+ if (DigitBits == 32 && length > 1) {
+ magnitude |= static_cast<uint64_t>(x->digit(1)) << 32;
+ }
+
+ if (x->isNegative()) {
+ constexpr uint64_t Int64MinMagnitude = uint64_t(1) << 63;
+ if (magnitude <= Int64MinMagnitude) {
+ *result = magnitude == Int64MinMagnitude
+ ? std::numeric_limits<int64_t>::min()
+ : -AssertedCast<int64_t>(magnitude);
+ return true;
+ }
+ } else {
+ if (magnitude <=
+ static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+ *result = AssertedCast<int64_t>(magnitude);
+ return true;
+ }
+ }
+
+ return false;
+}
+
// Compute `2**bits - (x & (2**bits - 1))`. Used when treating BigInt values as
// arbitrary-precision two's complement signed integers.
BigInt* BigInt::truncateAndSubFromPowerOfTwo(ExclusiveContext* cx, HandleBigInt x,
@@ -2661,7 +2699,7 @@ double BigInt::numberValue(BigInt* x) {
if (length <= 64 / DigitBits) {
uint64_t magnitude = x->digit(0);
if (DigitBits == 32 && length > 1) {
- magnitude |= uint64_t(x->digit(1)) << 32;
+ magnitude |= static_cast<uint64_t>(x->digit(1)) << 32;
}
const uint64_t MaxIntegralPrecisionDouble = uint64_t(1)
<< (SignificandWidth + 1);
diff --git a/js/src/vm/BigIntType.h b/js/src/vm/BigIntType.h
index 7cdd757994..ea0317fd9c 100644
--- a/js/src/vm/BigIntType.h
+++ b/js/src/vm/BigIntType.h
@@ -119,6 +119,11 @@ class BigInt final : public js::gc::TenuredCell {
static int64_t toInt64(BigInt* x);
static uint64_t toUint64(BigInt* x);
+ // Return true if the BigInt is without loss of precision representable as an
+ // int64 and store the int64 value in the output. Otherwise return false and
+ // leave the value of the output parameter unspecified.
+ static bool isInt64(BigInt* x, int64_t* result);
+
static BigInt* asIntN(js::ExclusiveContext* cx, Handle<BigInt*> x, uint64_t bits);
static BigInt* asUintN(js::ExclusiveContext* cx, Handle<BigInt*> x, uint64_t bits);