[JSC] Fix 32bit JSBigInt with INT32_MAX < x <= UINT32_MAX
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 May 2020 17:21:14 +0000 (17:21 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 May 2020 17:21:14 +0000 (17:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=212193

Reviewed by Mark Lam.

In 32bit architecture, we are creating one-length JSBigInt for INT32_MIN <= x <= INT32_MAX, and two-length JSBigInt otherwise.
This is wrong since one-length JSBigInt should cover from -UINT32_MAX <= x <= UINT32_MAX.

This patch fixes the bug and cleans up createFrom(VM&, int64_t). And it also adds JSBigInt::createFrom(VM&, uint64_t) in preparation for [1]
Currently, this path is not used while it was used previously because BigIntConstructor starts using JSBigInt::createFrom(VM&, double). But this
will be used in [1], and simply the existing implementation is wrong.

[1]: https://bugs.webkit.org/show_bug.cgi?id=190800

* runtime/JSBigInt.cpp:
(JSC::JSBigInt::createFromImpl):
(JSC::JSBigInt::createFrom):
* runtime/JSBigInt.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262012 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSBigInt.cpp
Source/JavaScriptCore/runtime/JSBigInt.h

index 4b6ad24..b6f9ba3 100644 (file)
@@ -1,3 +1,24 @@
+2020-05-21  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Fix 32bit JSBigInt with INT32_MAX < x <= UINT32_MAX
+        https://bugs.webkit.org/show_bug.cgi?id=212193
+
+        Reviewed by Mark Lam.
+
+        In 32bit architecture, we are creating one-length JSBigInt for INT32_MIN <= x <= INT32_MAX, and two-length JSBigInt otherwise.
+        This is wrong since one-length JSBigInt should cover from -UINT32_MAX <= x <= UINT32_MAX.
+
+        This patch fixes the bug and cleans up createFrom(VM&, int64_t). And it also adds JSBigInt::createFrom(VM&, uint64_t) in preparation for [1]
+        Currently, this path is not used while it was used previously because BigIntConstructor starts using JSBigInt::createFrom(VM&, double). But this
+        will be used in [1], and simply the existing implementation is wrong.
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=190800
+
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::createFromImpl):
+        (JSC::JSBigInt::createFrom):
+        * runtime/JSBigInt.h:
+
 2020-05-21  Paulo Matos  <pmatos@igalia.com>
 
         Further non-unified build fixes
index 35effd5..507ebc2 100644 (file)
@@ -135,43 +135,51 @@ JSBigInt* JSBigInt::createFrom(VM& vm, uint32_t value)
     return bigInt;
 }
 
-JSBigInt* JSBigInt::createFrom(VM& vm, int64_t value)
+inline JSBigInt* JSBigInt::createFromImpl(VM& vm, uint64_t value, bool sign)
 {
     if (!value)
         return createZero(vm);
 
     // This path is not just an optimization: because we do not call rightTrim at the end of this function,
     // it would be a bug to create a BigInt with length=2 in this case.
-    if (sizeof(Digit) == 8 || (value <= INT_MAX && value >= INT_MIN)) {
+    if (sizeof(Digit) == 8 || value <= UINT32_MAX) {
         JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
-        if (value < 0) {
-            bigInt->setDigit(0, static_cast<Digit>(static_cast<uint64_t>(-(value + 1)) + 1));
-            bigInt->setSign(true);
-        } else
-            bigInt->setDigit(0, static_cast<Digit>(value));
-        
+        bigInt->setDigit(0, static_cast<Digit>(value));
+        bigInt->setSign(sign);
         return bigInt;
     }
-    
+
+    ASSERT(sizeof(Digit) == 4);
     JSBigInt* bigInt = createWithLengthUnchecked(vm, 2);
-    uint64_t tempValue;
-    bool sign = false;
-    if (value < 0) {
-        tempValue = static_cast<uint64_t>(-(value + 1)) + 1;
-        sign = true;
-    } else
-        tempValue = value;
-    
-    Digit lowBits  = static_cast<Digit>(tempValue & 0xffffffff);
-    Digit highBits = static_cast<Digit>((tempValue >> 32) & 0xffffffff);
-    
+    Digit lowBits  = static_cast<Digit>(value & 0xffffffff);
+    Digit highBits = static_cast<Digit>((value >> 32) & 0xffffffff);
+
+    ASSERT(highBits);
+
     bigInt->setDigit(0, lowBits);
     bigInt->setDigit(1, highBits);
     bigInt->setSign(sign);
-    
+
     return bigInt;
 }
 
+JSBigInt* JSBigInt::createFrom(VM& vm, uint64_t value)
+{
+    return createFromImpl(vm, value, false);
+}
+
+JSBigInt* JSBigInt::createFrom(VM& vm, int64_t value)
+{
+    uint64_t unsignedValue;
+    bool sign = false;
+    if (value < 0) {
+        unsignedValue = static_cast<uint64_t>(-(value + 1)) + 1;
+        sign = true;
+    } else
+        unsignedValue = value;
+    return createFromImpl(vm, unsignedValue, sign);
+}
+
 JSBigInt* JSBigInt::createFrom(VM& vm, bool value)
 {
     if (!value)
index 70084a7..6bf8ab2 100644 (file)
@@ -72,6 +72,7 @@ public:
     JS_EXPORT_PRIVATE static JSBigInt* createFrom(VM&, int32_t value);
     static JSBigInt* createFrom(VM&, uint32_t value);
     static JSBigInt* createFrom(VM&, int64_t value);
+    static JSBigInt* createFrom(VM&, uint64_t value);
     static JSBigInt* createFrom(VM&, bool value);
     static JSBigInt* createFrom(VM&, double value);
 
@@ -427,6 +428,8 @@ public:
 private:
     JSBigInt(VM&, Structure*, Digit*, unsigned length);
 
+    static JSBigInt* createFromImpl(VM&, uint64_t value, bool sign);
+
     static constexpr unsigned bitsPerByte = 8;
     static constexpr unsigned digitBits = sizeof(Digit) * bitsPerByte;
     static constexpr unsigned halfDigitBits = digitBits / 2;