Ver Fonte

BigInt: implement bitwise not, negate

Z Nguyen-Huu há 7 anos atrás
pai
commit
974834f257

+ 33 - 0
lib/Runtime/Library/JavascriptBigInt.cpp

@@ -23,6 +23,13 @@ namespace Js
         return bigintNew;
     }
 
+    JavascriptBigInt * JavascriptBigInt::CreateOne(ScriptContext * scriptContext)
+    {
+        JavascriptBigInt * bigintNew = JavascriptBigInt::CreateZero(scriptContext);
+        bigintNew->m_digits[0] = 1;
+        return bigintNew;
+    }
+
     JavascriptBigInt * JavascriptBigInt::New(JavascriptBigInt * pbi, ScriptContext * scriptContext)
     {
         JavascriptBigInt * bigintNew = RecyclerNew(scriptContext->GetRecycler(), JavascriptBigInt, scriptContext->GetLibrary()->GetBigIntTypeStatic());
@@ -286,6 +293,32 @@ namespace Js
         return newBigInt;
     }
 
+    Var JavascriptBigInt::Not(Var aRight)
+    {
+        JavascriptBigInt* rightBigInt = VarTo<JavascriptBigInt>(aRight);
+        JavascriptBigInt* newBigInt = JavascriptBigInt::New(rightBigInt, rightBigInt->GetScriptContext());
+        JavascriptBigInt::Negate(newBigInt);
+        JavascriptBigInt * bigintOne = JavascriptBigInt::CreateOne(rightBigInt->GetScriptContext());
+        return JavascriptBigInt::Sub(newBigInt, bigintOne);
+    }
+
+    Var JavascriptBigInt::Negate(Var aRight)
+    {
+        JavascriptBigInt* rightBigInt = VarTo<JavascriptBigInt>(aRight);
+        JavascriptBigInt* newBigInt = JavascriptBigInt::New(rightBigInt, rightBigInt->GetScriptContext());
+        JavascriptBigInt::Negate(newBigInt);
+        return newBigInt;
+    }
+
+    void JavascriptBigInt::Negate(JavascriptBigInt * pbi)
+    {
+        if (JavascriptBigInt::IsZero(pbi))
+        {
+            return;
+        }
+        pbi->m_isNegative = !pbi->m_isNegative;
+    }
+
     // return low(a*b) and out high
     digit_t JavascriptBigInt::MulDigit(digit_t a, digit_t b, digit_t* resultHigh)
     {

+ 5 - 1
lib/Runtime/Library/JavascriptBigInt.h

@@ -40,10 +40,13 @@ namespace Js
         static Var Add(Var aLeft, Var aRight);
         static Var Sub(Var aLeft, Var aRight);
         static Var Decrement(Var aRight);
+        static Var Not(Var aRight);
+        static Var Negate(Var aRight);
 
         inline BOOL isNegative() { return m_isNegative; }
 
         static JavascriptBigInt * CreateZero(ScriptContext * scriptContext);
+        static JavascriptBigInt * CreateOne(ScriptContext * scriptContext);
         static JavascriptBigInt * Create(const char16 * content, charcount_t cchUseLength, bool isNegative, ScriptContext * scriptContext);
         virtual RecyclableObject * CloneToScriptContext(ScriptContext* requestContext) override;
 
@@ -71,8 +74,9 @@ namespace Js
         static bool IsZero(JavascriptBigInt * pbi);
         static void AbsoluteIncrement(JavascriptBigInt * pbi);
         static void AbsoluteDecrement(JavascriptBigInt * pbi);
-        static void Increment(JavascriptBigInt * aValue);
+        static void Increment(JavascriptBigInt * pbi);
         static void Decrement(JavascriptBigInt * pbi);
+        static void Negate(JavascriptBigInt * pbi);
         static JavascriptBigInt * Add(JavascriptBigInt * pbi1, JavascriptBigInt * pbi2);
         static void AddAbsolute(JavascriptBigInt * pbi1, JavascriptBigInt * pbi2);
         static JavascriptBigInt * Sub(JavascriptBigInt * pbi1, JavascriptBigInt * pbi2);

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

@@ -13,6 +13,11 @@ using namespace Js;
                 return scriptContext->GetLibrary()->GetNegativeZero();
             }
 
+            if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
+            {
+                return JavascriptBigInt::Negate(aRight);
+            }
+
             double value = Negate_Helper(aRight, scriptContext);
             return JavascriptNumber::ToVarIntCheck(value, scriptContext);
             JIT_HELPER_END(Op_Negate_Full);
@@ -28,6 +33,11 @@ using namespace Js;
                 return scriptContext->GetLibrary()->GetNegativeZero();
             }
 
+            if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
+            {
+                return JavascriptBigInt::Negate(aRight);
+            }
+
             double value = Negate_Helper(aRight, scriptContext);
             return JavascriptNumber::InPlaceNew(value, scriptContext, result);
             JIT_HELPER_END(Op_NegateInPlace);
@@ -39,6 +49,11 @@ using namespace Js;
 #if _M_IX86
             AssertMsg(!TaggedInt::Is(aRight), "Should be detected");
 #endif
+            if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
+            {
+                return JavascriptBigInt::Not(aRight);
+            }
+
             int nValue = JavascriptConversion::ToInt32(aRight, scriptContext);
             return JavascriptNumber::ToVar(~nValue, scriptContext);
             JIT_HELPER_END(Op_Not_Full);
@@ -50,6 +65,11 @@ using namespace Js;
             JIT_HELPER_REENTRANT_HEADER(Op_NotInPlace);
             AssertMsg(!TaggedInt::Is(aRight), "Should be detected");
 
+            if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
+            {
+                return JavascriptBigInt::Not(aRight);
+            }
+
             int nValue = JavascriptConversion::ToInt32(aRight, scriptContext);
             return JavascriptNumber::ToVarInPlace(~nValue, scriptContext, result);
             JIT_HELPER_END(Op_NotInPlace);

+ 72 - 0
test/BigInt/bitwise_not.js

@@ -0,0 +1,72 @@
+//-------------------------------------------------------------------------------------------------------
+// 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: "BigInt literal",
+        body: function () {
+            var x = ~123n;
+            assert.isTrue(x == -124n);
+        }
+    },
+    {
+        name: "Negative BigInt literal",
+        body: function () {
+            var x = ~-123n;
+            assert.isTrue(x == 122n);
+        }
+    },   
+    {
+        name: "0n",
+        body: function () {
+            var x = ~0n;
+            assert.isTrue(x == -1n);
+        }
+    },
+    {
+        name: "BigInt Object",
+        body: function () {
+            var x = ~BigInt(12345n);
+            var y = BigInt(-12346n);
+            assert.isTrue(x == y);
+        }
+    },
+    {
+        name: "Out of 64 bit range",
+        body: function () {
+            var x = ~1234567890123456789012345678901234567890n;
+            var y = -1234567890123456789012345678901234567891n;
+            assert.isTrue(x == y);
+        }
+    },
+    {
+        name: "Very big",
+        body: function () {
+            var x = eval('1234567890'.repeat(20)+'0n');
+            var y = -x-1n;
+            var z = ~x;
+            assert.isTrue(z == y);
+        }
+    },
+    {
+        name: "With assign",
+        body: function () {
+            var x = 3n;
+            var y = x;
+            assert.isTrue(x == 3n);
+            assert.isTrue(y == 3n);
+            y = ~x;            
+            assert.isTrue(x == 3n);
+            assert.isTrue(y == -4n);
+        }
+    },
+];
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 6 - 0
test/BigInt/rlexe.xml

@@ -54,4 +54,10 @@
       <compile-flags>-args summary -endargs -ESBigInt</compile-flags>
     </default>
   </test>
+    <test>
+    <default>
+      <files>bitwise_not.js</files>
+      <compile-flags>-args summary -endargs -ESBigInt</compile-flags>
+    </default>
+  </test>
 </regress-exe>