Quellcode durchsuchen

implement dymamic memory allocation, imcrement and decrement with bigint

change to digit_t

add nativetest for add,sub,mul with digit
Duong Nguyen-Huu vor 7 Jahren
Ursprung
Commit
88ce20f92b

+ 12 - 0
bin/ChakraCore/TestHooks.cpp

@@ -19,6 +19,13 @@ int LogicalStringCompareImpl(const char16* p1, int p1size, const char16* p2, int
 }
 }
 
+namespace Js
+{
+    static digit_t AddDigit(digit_t a, digit_t b, digit_t * carry);
+    static digit_t SubtractDigit(digit_t a, digit_t b, digit_t * borrow);
+    static digit_t MulDigit(digit_t a, digit_t b, digit_t * high);
+}
+
 #ifdef ENABLE_TEST_HOOKS
 
 HRESULT __stdcall SetConfigFlags(__in int argc, __in_ecount(argc) LPWSTR argv[], ICustomConfigFlags* customConfigFlags)
@@ -168,6 +175,11 @@ HRESULT OnChakraCoreLoaded(OnChakraCoreLoadedPtr pfChakraCoreLoaded)
         SetEnableCheckMemoryLeakOutput,
         PlatformAgnostic::UnicodeText::Internal::LogicalStringCompareImpl,
 
+        //BigInt hooks
+        Js::JavascriptBigInt::AddDigit,
+        Js::JavascriptBigInt::SubDigit,
+        Js::JavascriptBigInt::MulDigit,
+
 #define FLAG(type, name, description, defaultValue, ...) FLAG_##type##(name)
 #define FLAGINCLUDE(name) \
     IsEnabled##name##Flag, \

+ 8 - 0
bin/ChakraCore/TestHooks.h

@@ -31,6 +31,14 @@ struct TestHooks
     SetEnableCheckMemoryLeakOutputPtr pfSetEnableCheckMemoryLeakOutput;
     LogicalStringCompareImpl pfLogicalCompareStringImpl;
 
+    // Javasscript Bigint hooks
+    typedef digit_t(TESTHOOK_CALL *AddDigit)(digit_t a, digit_t b, digit_t* carry);
+    typedef digit_t(TESTHOOK_CALL *SubDigit)(digit_t a, digit_t b, digit_t* borrow);
+    typedef digit_t(TESTHOOK_CALL *MulDigit)(digit_t a, digit_t b, digit_t* high);
+    AddDigit pfAddDigit;
+    SubDigit pfSubDigit;
+    MulDigit pfMulDigit;
+
 #define FLAG(type, name, description, defaultValue, ...) FLAG_##type##(name)
 #define FLAG_String(name) \
     bool (TESTHOOK_CALL *pfIsEnabled##name##Flag)(); \

+ 84 - 0
bin/NativeTests/JavascriptBigIntTests.cpp

@@ -0,0 +1,84 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+#include "stdafx.h"
+#pragma warning(disable:26434) // Function definition hides non-virtual function in base class
+#pragma warning(disable:26439) // Implicit noexcept
+#pragma warning(disable:26451) // Arithmetic overflow
+#pragma warning(disable:26495) // Uninitialized member variable
+#include "catch.hpp"
+
+#pragma warning(disable:4100) // unreferenced formal parameter
+#pragma warning(disable:6387) // suppressing preFAST which raises warning for passing null to the JsRT APIs
+#pragma warning(disable:6262) // CATCH is using stack variables to report errors, suppressing the preFAST warning.
+
+namespace JavascriptBigIntTests
+{
+    void Test_AddDigit(digit_t digit1, digit_t digit2, digit_t * carry, digit_t expectedResult, digit_t expectedCarry)
+    {
+        REQUIRE(g_testHooksLoaded);
+
+        digit_t res = g_testHooks.pfAddDigit(digit1, digit2, carry);
+
+        //test to check that the result from call to AddDigit is the expected value
+        REQUIRE(res == expectedResult);
+        REQUIRE(expectedCarry == *carry);
+    }
+
+    void Test_SubDigit(digit_t digit1, digit_t digit2, digit_t * borrow, digit_t expectedResult, digit_t expectedBorrow)
+    {
+        REQUIRE(g_testHooksLoaded);
+
+        digit_t res = g_testHooks.pfSubDigit(digit1, digit2, borrow);
+
+        //test to check that the result from call to SubtractDigit is the expected value
+        REQUIRE(res == expectedResult);
+        REQUIRE(*borrow == expectedBorrow);
+    }
+
+    void Test_MulDigit(digit_t digit1, digit_t digit2, digit_t * high, digit_t expectedResult, digit_t expectedHigh)
+    {
+        REQUIRE(g_testHooksLoaded);
+
+        digit_t res = g_testHooks.pfMulDigit(digit1, digit2, high);
+
+        //test to check that the result from call to SubtractDigit is the expected value
+        REQUIRE(res == expectedResult);
+        REQUIRE(*high == expectedHigh);
+    }
+
+    TEST_CASE("AddDigit", "[JavascriptBigIntTests]")
+    {
+        digit_t carry = 0;
+        Test_AddDigit(1, 2, &carry, 3, 0);
+
+        digit_t d1 = UINTPTR_MAX;
+        digit_t d2 = UINTPTR_MAX;
+        carry = 0;
+        Test_AddDigit(d1, d2, &carry, UINTPTR_MAX-1, 1);
+    }
+
+    TEST_CASE("SubDigit", "[JavascriptBigIntTests]")
+    {
+        digit_t borrow = 0;
+        Test_SubDigit(3, 2, &borrow, 1, 0);
+
+        digit_t d1 = 0;
+        digit_t d2 = 1;
+        borrow = 0;
+        Test_SubDigit(d1, d2, &borrow, UINTPTR_MAX, 1);
+    }
+
+    TEST_CASE("MulDigit", "[JavascriptBigIntTests]")
+    {
+        digit_t high = 0;
+        Test_MulDigit(3, 2, &high, 6, 0);
+
+        digit_t d1 = UINTPTR_MAX;
+        digit_t d2 = 2;
+        high = 0;
+        Test_MulDigit(d1, d2, &high, UINTPTR_MAX-1, 1);
+    }
+}

+ 1 - 0
bin/NativeTests/NativeTests.vcxproj

@@ -48,6 +48,7 @@
     <ClInclude Include="stdafx.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="JavascriptBigIntTests.cpp" />
     <ClCompile Include="BigUIntTest.cpp" />
     <ClCompile Include="CodexAssert.cpp" />
     <ClCompile Include="CodexTests.cpp" />

+ 3 - 0
lib/Common/Core/CommonTypedefs.h

@@ -61,3 +61,6 @@ namespace Js
 {
     typedef uint32 LocalFunctionId;
 };
+
+// digit_t represents a digit in bigint underline
+typedef uintptr_t digit_t;

+ 212 - 17
lib/Runtime/Library/JavascriptBigInt.cpp

@@ -11,6 +11,23 @@ namespace Js
         return RecyclerNew(scriptContext->GetRecycler(), JavascriptBigInt, content, cchUseLength, isNegative, scriptContext->GetLibrary()->GetBigIntTypeStatic());
     }
 
+    JavascriptBigInt * JavascriptBigInt::New(JavascriptBigInt * pbi, ScriptContext * scriptContext)
+    {
+        JavascriptBigInt * bigintNew = RecyclerNew(scriptContext->GetRecycler(), JavascriptBigInt, scriptContext->GetLibrary()->GetBigIntTypeStatic());
+        bigintNew->m_length = pbi->m_length;
+        bigintNew->m_maxLength = pbi->m_maxLength;
+        bigintNew->m_isNegative = pbi->m_isNegative;
+        bigintNew->m_digits = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), digit_t, pbi->m_length);
+        js_memcpy_s(bigintNew->m_digits, bigintNew->m_length * sizeof(digit_t), pbi->m_digits, bigintNew->m_length * sizeof(digit_t));
+ 
+        return bigintNew;
+    }
+
+    RecyclableObject * JavascriptBigInt::CloneToScriptContext(ScriptContext* requestContext)
+    {
+        return JavascriptBigInt::New(this, requestContext);
+    }
+
     Var JavascriptBigInt::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
     {
         PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
@@ -71,21 +88,52 @@ namespace Js
         return true;
     }
 
+    bool JavascriptBigInt::Resize(digit_t length)
+    {
+        digit_t *digits;
+
+        if (length <= m_maxLength)
+        {
+            return true;
+        }
+
+        length += length;// double size
+        if (SIZE_MAX / sizeof(digit_t) < length) // overflow 
+        {
+            return false;
+        }
+
+        digits = RecyclerNewArrayLeaf(this->GetScriptContext()->GetRecycler(), digit_t, length);
+        if (NULL == digits)
+        {
+            return false;
+        }
+
+        if (0 < m_length) // in this case, we need to copy old data over
+        {
+            js_memcpy_s(digits, length * sizeof(digit_t), m_digits, m_length * sizeof(digit_t));
+        }
+
+        m_digits = digits;
+        m_maxLength = length;
+
+        return true;
+    }
+
     template <typename EncodedChar>
     void JavascriptBigInt::InitFromCharDigits(const EncodedChar *pChar, uint32 charLength, bool isNegative)
     {
         Assert(charLength >= 0);
         Assert(pChar != 0);
-        AssertMsg(charLength <= MaxStringLength, "do not support BigInt out of the range");
 
         const EncodedChar *pCharLimit = pChar + charLength - 1;//'n' at the end
 
         m_length = 0;
-        m_digits = m_reservedDigitsInit;
+        m_digits = RecyclerNewArrayLeaf(this->GetScriptContext()->GetRecycler(), digit_t, m_maxLength);
         m_isNegative = isNegative;
 
-        uint32 digitMul = 1;
-        uint32 digitAdd = 0;
+        digit_t digitMul = 1;
+        digit_t digitAdd = 0;
         bool check = true;
         for (; pChar < pCharLimit; pChar++)
         {
@@ -113,26 +161,177 @@ namespace Js
         }
     }
 
-    bool JavascriptBigInt::MulThenAdd(uint32 digitMul, uint32 digitAdd)
+    // return low(a+b) and out carry
+    digit_t JavascriptBigInt::AddDigit(digit_t a, digit_t b, digit_t* carry)
+    {
+        digit_t result = a + b;
+        if (result < a)
+        {
+            *carry += 1;
+        }
+        return result;
+    }
+
+    // return low(a+b) and out carry
+    digit_t JavascriptBigInt::SubDigit(digit_t a, digit_t b, digit_t* borrow)
+    {
+        digit_t result = a - b;
+        if (result > a)
+        {
+            *borrow += 1;
+        }
+        return result;
+    }
+
+    bool JavascriptBigInt::IsZero(JavascriptBigInt * pbi)
+    {
+        return (pbi->m_length == 1 && pbi->m_digits[0] == 0);
+    }
+
+    void JavascriptBigInt::AbsoluteIncrement(JavascriptBigInt * pbi)
+    {
+        JavascriptBigInt* result = pbi;
+        digit_t carry = 1;
+        for (digit_t i = 0; i < result->m_length && carry > 0; i++)
+        {
+            digit_t tempCarry = 0;
+            result->m_digits[i] = JavascriptBigInt::AddDigit(result->m_digits[i], carry, &tempCarry);
+            carry = tempCarry;
+        }
+        if (carry > 0) //increase length
+        {
+            if (result->m_length >= result->m_maxLength && !result->Resize(result->m_length + 1))
+            {
+                AssertOrFailFastMsg(false, "AbsoluteIncrement overflow");
+            }
+            result->m_digits[result->m_length++] = carry;
+        }
+    }
+
+    void JavascriptBigInt::AbsoluteDecrement(JavascriptBigInt * pbi)
+    {
+        JavascriptBigInt* result = pbi;
+        Assert(!JavascriptBigInt::IsZero(result));
+        digit_t borrow = 1;
+        for (digit_t i = 0; i < result->m_length && borrow > 0; i++)
+        {
+            digit_t tempBorrow = 0;
+            result->m_digits[i] = JavascriptBigInt::SubDigit(result->m_digits[i], borrow, &tempBorrow);
+            borrow = tempBorrow;
+        }
+        Assert(borrow == 0);
+        // remove trailing zero
+        if (result->m_digits[result->m_length-1] == 0)
+        {
+            result->m_length--;
+        }
+    }
+
+    void JavascriptBigInt::Increment(JavascriptBigInt * pbi)
+    {
+        if (pbi->m_isNegative)
+        {
+            // return 0n for -1n
+            if (pbi->m_length == 1 && pbi->m_digits[0] == 1)
+            {
+                JavascriptBigInt* result = pbi;
+                result->m_digits[0] = 0;
+                result->m_isNegative = false;
+                return;
+            }
+            return JavascriptBigInt::AbsoluteDecrement(pbi);
+        }
+        return JavascriptBigInt::AbsoluteIncrement(pbi);
+    }
+
+    void JavascriptBigInt::Decrement(JavascriptBigInt * pbi)
+    {
+        if (pbi->m_isNegative)
+        {
+            return JavascriptBigInt::AbsoluteIncrement(pbi);
+        }
+        if (JavascriptBigInt::IsZero(pbi)) // return -1n for 0n
+        {
+            JavascriptBigInt* result = pbi;
+            result->m_digits[0] = 1;
+            result->m_isNegative = true;
+            return;
+        }
+        return JavascriptBigInt::AbsoluteDecrement(pbi);
+    }
+
+    Var JavascriptBigInt::Increment(Var aRight)
+    {
+        JavascriptBigInt* rightBigInt = VarTo<JavascriptBigInt>(aRight);
+        JavascriptBigInt* newBigInt = JavascriptBigInt::New(rightBigInt, rightBigInt->GetScriptContext());
+        JavascriptBigInt::Increment(newBigInt);
+        return newBigInt;
+    }
+
+    Var JavascriptBigInt::Decrement(Var aRight)
+    {
+        JavascriptBigInt* rightBigInt = VarTo<JavascriptBigInt>(aRight);
+        JavascriptBigInt* newBigInt = JavascriptBigInt::New(rightBigInt, rightBigInt->GetScriptContext());
+        JavascriptBigInt::Decrement(newBigInt);
+        return newBigInt;
+    }
+
+    // return low(a*b) and out high
+    digit_t JavascriptBigInt::MulDigit(digit_t a, digit_t b, digit_t* resultHigh)
+    {
+        // Multiply is performed in half chuck favor.
+        // For inputs [AH AL]*[BH BL], the result is:
+        //
+        //            [AL*BL]  // rLow
+        //    +    [AL*BH]     // rMid1
+        //    +    [AH*BL]     // rMid2
+        //    + [AH*BH]        // rHigh
+        //    = [R1 R2 R3 R4]  // high = [R1 R2], low = [R3 R4]
+        //
+
+        digit_t kHalfDigitBits = sizeof(digit_t) * 4;
+        digit_t kHalfDigitMask = ((digit_t)1 << kHalfDigitBits) - 1;
+
+        digit_t aLow = a & kHalfDigitMask;
+        digit_t aHigh = a >> kHalfDigitBits;
+        digit_t bLow = b & kHalfDigitMask;
+        digit_t bHigh = b >> kHalfDigitBits;
+
+        digit_t rLow = aLow * bLow;
+        digit_t rMid1 = aLow * bHigh;
+        digit_t rMid2 = aHigh * bLow;
+        digit_t rHigh = aHigh * bHigh;
+
+        digit_t carry = 0;
+        digit_t resultLow = JavascriptBigInt::AddDigit(rLow, rMid1 << kHalfDigitBits, &carry);
+        resultLow = JavascriptBigInt::AddDigit(resultLow, rMid2 << kHalfDigitBits, &carry);
+        *resultHigh = (rMid1 >> kHalfDigitBits) + (rMid2 >> kHalfDigitBits) + rHigh + carry;
+        return resultLow;
+    }
+
+    bool JavascriptBigInt::MulThenAdd(digit_t digitMul, digit_t digitAdd)
     {
         Assert(digitMul != 0);
 
-        uint32 carryDigit = 0;
-        uint32 *pDigit = m_digits;
-        uint32 *pDigitLimit = pDigit + m_length;
+        digit_t carryDigit = 0;
+        digit_t *pDigit = m_digits;
+        digit_t *pDigitLimit = pDigit + m_length;
 
         for (; pDigit < pDigitLimit; pDigit++)
         {
-            *pDigit = NumberUtilities::MulLu(*pDigit, digitMul, &carryDigit);// return low Digit to digit, hight Digit to carry
+            *pDigit = JavascriptBigInt::MulDigit(*pDigit, digitMul, &carryDigit);// return low Digit to digit, hight Digit to carry
             if (digitAdd > 0)
             {
-                carryDigit += NumberUtilities::AddLu(pDigit, digitAdd);// add carry to result
+                *pDigit = JavascriptBigInt::AddDigit(*pDigit, digitAdd, &carryDigit);// add carry to result
             }
             digitAdd = carryDigit;
         }
         if (0 < digitAdd) // length increase by 1
         {
-            AssertOrFailFast(m_length < MaxDigitLength);// check out of bound
+            if (m_length >= m_maxLength && !Resize(m_length + 1))
+            {
+                return false;
+            }
             m_digits[m_length++] = digitAdd;
         }
         return true;
@@ -152,7 +351,7 @@ namespace Js
             }
         }
 
-        uint32 index;
+        digit_t index;
         int sign = m_isNegative ? -1 : 1;
 
         if (m_length > pbi->m_length)
@@ -181,7 +380,7 @@ namespace Js
 
     bool JavascriptBigInt::LessThan(Var aLeft, Var aRight)
     {
-        AssertMsg(VarIs<JavascriptBigInt>(aLeft) && VarIs<JavascriptBigInt>(aRight), "BigInt Equals");
+        AssertMsg(VarIs<JavascriptBigInt>(aLeft) && VarIs<JavascriptBigInt>(aRight), "BigInt LessThan");
 
         JavascriptBigInt *leftBigInt = VarTo<JavascriptBigInt>(aLeft);
         JavascriptBigInt *rightBigInt = VarTo<JavascriptBigInt>(aRight);
@@ -192,14 +391,10 @@ namespace Js
     bool JavascriptBigInt::Equals(Var aLeft, Var aRight)
     {
         AssertMsg(VarIs<JavascriptBigInt>(aLeft) && VarIs<JavascriptBigInt>(aRight), "BigInt Equals");
-
         JavascriptBigInt *leftBigInt = VarTo<JavascriptBigInt>(aLeft);
         JavascriptBigInt *rightBigInt = VarTo<JavascriptBigInt>(aRight);
 
         return (leftBigInt->Compare(rightBigInt) == 0);
     }
 
-    template void JavascriptBigInt::InitFromCharDigits<char16>(const char16 *pChar, uint32 charLength, bool isNegative);
-    template void JavascriptBigInt::InitFromCharDigits<utf8char_t>(const utf8char_t *pChar, uint32 charLength, bool isNegative);
-
 } // namespace Js

+ 23 - 10
lib/Runtime/Library/JavascriptBigInt.h

@@ -4,26 +4,24 @@
 //-------------------------------------------------------------------------------------------------------
 #pragma once
 
+
 namespace Js
 {
     class JavascriptBigInt sealed : public RecyclableObject
     {
-
     private:
-        Field(uint32*) m_digits;         // digits
-        Field(uint32) m_length;          // length
+        Field(digit_t*) m_digits;         // digits
+        Field(digit_t) m_length;          // length
+        Field(digit_t) m_maxLength;          // max length without resize
         Field(bool) m_isNegative;
 
-        // TODO: BigInt should be arbitrary-precision, need to resize space and add tagged BigInt
-        static const uint32 MaxStringLength = 100; // Max String length
-        static const uint32 MaxDigitLength = 20;  // Max Digit length 
-        Field(uint32) m_reservedDigitsInit[MaxDigitLength]; // pre-defined space to store array
+        static const digit_t InitDigitLength = 2;  // Max Digit length 
 
         DEFINE_VTABLE_CTOR(JavascriptBigInt, RecyclableObject);
 
     public:
         JavascriptBigInt(StaticType * type)
-            : RecyclableObject(type), m_length(0), m_digits(nullptr), m_isNegative(false)
+            : RecyclableObject(type), m_length(0), m_digits(nullptr), m_isNegative(false), m_maxLength(InitDigitLength)
         {
             Assert(type->GetTypeId() == TypeIds_BigInt);
         }
@@ -38,10 +36,13 @@ namespace Js
 
         static bool LessThan(Var aLeft, Var aRight);
         static bool Equals(Var aLeft, Var aRight);
+        static Var Increment(Var aRight);
+        static Var Decrement(Var aRight);
 
         inline BOOL isNegative() { return m_isNegative; }
 
         static JavascriptBigInt * Create(const char16 * content, charcount_t cchUseLength, bool isNegative, ScriptContext * scriptContext);
+        virtual RecyclableObject * CloneToScriptContext(ScriptContext* requestContext) override;
 
         class EntryInfo
         {
@@ -55,15 +56,27 @@ namespace Js
 
         virtual BOOL Equals(Var other, BOOL* value, ScriptContext * requestContext) override;
 
+        static digit_t AddDigit(digit_t a, digit_t b, digit_t * carry);
+        static digit_t SubDigit(digit_t a, digit_t b, digit_t * borrow);
+        static digit_t MulDigit(digit_t a, digit_t b, digit_t * high);
+
     private:
         template <typename EncodedChar>
         void InitFromCharDigits(const EncodedChar *prgch, uint32 cch, bool isNegative); // init from char of digits
 
-        bool MulThenAdd(uint32 luMul, uint32 luAdd);
+        bool MulThenAdd(digit_t luMul, digit_t luAdd);
+        static bool IsZero(JavascriptBigInt * pbi);
+        static void AbsoluteIncrement(JavascriptBigInt * pbi);
+        static void AbsoluteDecrement(JavascriptBigInt * pbi);
+        static void Increment(JavascriptBigInt * aValue);
+        static void Decrement(JavascriptBigInt * pbi);
         int Compare(JavascriptBigInt * pbi);
         static BOOL Equals(JavascriptBigInt* left, Var right, BOOL* value, ScriptContext * requestContext);
-    };
+        bool Resize(digit_t length);
 
+        static JavascriptBigInt * New(JavascriptBigInt * pbi, ScriptContext * scriptContext);
+    };
+    
     template <> inline bool VarIsImpl<JavascriptBigInt>(RecyclableObject* obj)
     {
         return JavascriptOperators::GetTypeId(obj) == TypeIds_BigInt;

+ 16 - 0
lib/Runtime/Math/JavascriptMath.cpp

@@ -62,6 +62,10 @@ using namespace Js;
             {
                 return TaggedInt::Increment(aRight, scriptContext);
             }
+            if (VarIs<JavascriptBigInt>(aRight))
+            {
+                return JavascriptBigInt::Increment(aRight);
+            }
 
             double inc = Increment_Helper(aRight, scriptContext);
             return JavascriptNumber::InPlaceNew(inc, scriptContext, result);
@@ -75,6 +79,10 @@ using namespace Js;
             {
                 return TaggedInt::Increment(aRight, scriptContext);
             }
+            if (VarIs<JavascriptBigInt>(aRight))
+            {
+                return JavascriptBigInt::Increment(aRight);
+            }
 
             double inc = Increment_Helper(aRight, scriptContext);
             return JavascriptNumber::ToVarIntCheck(inc, scriptContext);
@@ -89,6 +97,10 @@ using namespace Js;
             {
                 return TaggedInt::Decrement(aRight, scriptContext);
             }
+            if (VarIs<JavascriptBigInt>(aRight))
+            {
+                return JavascriptBigInt::Decrement(aRight);
+            }
 
             double dec = Decrement_Helper(aRight,scriptContext);
             return JavascriptNumber::InPlaceNew(dec, scriptContext, result);
@@ -102,6 +114,10 @@ using namespace Js;
             {
                 return TaggedInt::Decrement(aRight, scriptContext);
             }
+            if (VarIs<JavascriptBigInt>(aRight))
+            {
+                return JavascriptBigInt::Decrement(aRight);
+            }
 
             double dec = Decrement_Helper(aRight,scriptContext);
             return JavascriptNumber::ToVarIntCheck(dec, scriptContext);

+ 46 - 0
test/BigInt/assign_by_value.js

@@ -0,0 +1,46 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+
+if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
+    this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+}
+
+var tests = [
+    {
+        name: "Assign BigInt literal",
+        body: function () {
+            var x = 123n;
+            var y = x;
+            assert.isTrue(x == 123n);
+            assert.isTrue(y == 123n);
+            x++;
+            assert.isTrue(x == 124n);
+            assert.isTrue(y == 123n);
+            y = x;
+            ++x;
+            assert.isTrue(x == 125n);
+            assert.isTrue(y == 124n);
+        }
+    },
+    {
+        name: "Assign BigInt object",
+        body: function () {
+            var x = BigInt(123n);
+            var y = x;
+            assert.isTrue(x == 123n);
+            assert.isTrue(y == 123n);
+            x++;
+            assert.isTrue(x == 124n);
+            assert.isTrue(y == 123n);
+            y = x;
+            ++x;
+            assert.isTrue(x == 125n);
+            assert.isTrue(y == 124n);
+        }
+    },
+];
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 26 - 0
test/BigInt/comparison.js

@@ -72,6 +72,32 @@ var tests = [
             assert.isFalse(x > y);
         }
     },
+    {
+        name: "Out of 64 bit range",
+        body: function () {
+            var x = 1234567890123456789012345678901234567890n;
+            var y = BigInt(1234567890123456789012345678901234567891n);
+            assert.isFalse(x == y);
+            assert.isTrue(x < y);
+            assert.isTrue(x <= y);
+            assert.isTrue(x == x);
+            assert.isFalse(x >= y);
+            assert.isFalse(x > y);
+        }
+    },
+    {
+        name: "Very big BigInt, test resize",
+        body: function () {
+            var x = eval('1234567890'.repeat(20) + 'n');
+            var y = eval('1234567891'.repeat(20) + 'n');
+            assert.isFalse(x == y);
+            assert.isTrue(x < y);
+            assert.isTrue(x <= y);
+            assert.isTrue(x == x);
+            assert.isFalse(x >= y);
+            assert.isFalse(x > y);
+        }
+    },
 ];
 
 testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 89 - 0
test/BigInt/decrement.js

@@ -0,0 +1,89 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+
+if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
+    this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+}
+
+var tests = [
+    {
+        name: "Decrement BigInt literal",
+        body: function () {
+            var x = 123n;
+            assert.isTrue(x == 123n);
+            x--;
+            assert.isTrue(x == 122n);
+            --x;
+            assert.isTrue(x == 121n);
+        }
+    },
+    {
+        name: "Decrement negative BigInt literal",
+        body: function () {
+            var x = -123n;
+            assert.isTrue(x == -123n);
+            x--;
+            assert.isTrue(x == -124n);
+            --x;
+            assert.isTrue(x == -125n);
+        }
+    },   
+    {
+        name: "Decrement 0n",
+        body: function () {
+            var x = 0n;
+            assert.isTrue(x == 0n);
+            x--;
+            assert.isTrue(x == -1n);
+            --x;
+            assert.isTrue(x == -2n);
+        }
+    },
+    {
+        name: "Decrement to change length",
+        body: function () {
+            var x = 4294967296n;
+            assert.isTrue(x == 4294967296n);
+            x--;
+            assert.isTrue(x == 4294967295n);
+            --x;
+            assert.isTrue(x == 4294967294n);
+            var y = -4294967295n;
+            assert.isTrue(y == -4294967295n);
+            y--;
+            assert.isTrue(y == -4294967296n);
+            --y;
+            assert.isTrue(y == -4294967297n);
+        }
+    },
+    {
+        name: "Decrement BigInt Object",
+        body: function () {
+            var x = BigInt(12345678901234567890n);
+            var y = BigInt(12345678901234567891n);
+            assert.isTrue(x < y);
+            --y;
+            assert.isTrue(x == y);
+            y--;
+            assert.isTrue(x >= y);
+        }
+    },
+    {
+        name: "Out of 64 bit range",
+        body: function () {
+            var x = 1234567890123456789012345678901234567890n;
+            var y = BigInt(1234567890123456789012345678901234567891n);
+            assert.isFalse(x == y);
+            x--;
+            --y;
+            assert.isTrue(x < y);
+            --y;
+            assert.isTrue(x == y);
+        }
+    },
+];
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 89 - 0
test/BigInt/increment.js

@@ -0,0 +1,89 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+
+if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
+    this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+}
+
+var tests = [
+    {
+        name: "Increment BigInt literal",
+        body: function () {
+            var x = 123n;
+            assert.isTrue(x == 123n);
+            x++;
+            assert.isTrue(x == 124n);
+            ++x;
+            assert.isTrue(x == 125n);
+        }
+    },
+    {
+        name: "Increment negative BigInt literal",
+        body: function () {
+            var x = -123n;
+            assert.isTrue(x == -123n);
+            x++;
+            assert.isTrue(x == -122n);
+            ++x;
+            assert.isTrue(x == -121n);
+        }
+    },   
+    {
+        name: "Increment -1n",
+        body: function () {
+            var x = -1n;
+            assert.isTrue(x == -1n);
+            x++;
+            assert.isTrue(x == 0n);
+            ++x;
+            assert.isTrue(x == 1n);
+        }
+    },
+    {
+        name: "Increment to change length",
+        body: function () {
+            var x = 4294967295n;
+            assert.isTrue(x == 4294967295n);
+            x++;
+            assert.isTrue(x == 4294967296n);
+            ++x;
+            assert.isTrue(x == 4294967297n);
+            var y = -4294967297n;
+            assert.isTrue(y == -4294967297n);
+            y++;
+            assert.isTrue(y == -4294967296n);
+            ++y;
+            assert.isTrue(y == -4294967295n);
+        }
+    },
+    {
+        name: "Increment BigInt Object",
+        body: function () {
+            var x = BigInt(12345678901234567890n);
+            var y = BigInt(12345678901234567891n);
+            assert.isTrue(x < y);
+            ++x;
+            assert.isTrue(x == y);
+            x++;
+            assert.isTrue(x >= y);
+        }
+    },
+    {
+        name: "Out of 64 bit range",
+        body: function () {
+            var x = 1234567890123456789012345678901234567890n;
+            var y = BigInt(1234567890123456789012345678901234567891n);
+            assert.isFalse(x == y);
+            x++;
+            ++y;
+            assert.isTrue(x < y);
+            ++x;
+            assert.isTrue(x == y);
+        }
+    },
+];
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 18 - 0
test/BigInt/rlexe.xml

@@ -12,4 +12,22 @@
       <compile-flags>-args summary -endargs -ESBigInt</compile-flags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>increment.js</files>
+      <compile-flags>-args summary -endargs -ESBigInt</compile-flags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>decrement.js</files>
+      <compile-flags>-args summary -endargs -ESBigInt</compile-flags>
+    </default>
+  </test>
+    <test>
+    <default>
+      <files>assign_by_value.js</files>
+      <compile-flags>-args summary -endargs -ESBigInt</compile-flags>
+    </default>
+  </test>
 </regress-exe>