Skip to content

Commit 974834f

Browse files
committed
BigInt: implement bitwise not, negate
1 parent 87766f5 commit 974834f

File tree

5 files changed

+136
-1
lines changed

5 files changed

+136
-1
lines changed

lib/Runtime/Library/JavascriptBigInt.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ namespace Js
2323
return bigintNew;
2424
}
2525

26+
JavascriptBigInt * JavascriptBigInt::CreateOne(ScriptContext * scriptContext)
27+
{
28+
JavascriptBigInt * bigintNew = JavascriptBigInt::CreateZero(scriptContext);
29+
bigintNew->m_digits[0] = 1;
30+
return bigintNew;
31+
}
32+
2633
JavascriptBigInt * JavascriptBigInt::New(JavascriptBigInt * pbi, ScriptContext * scriptContext)
2734
{
2835
JavascriptBigInt * bigintNew = RecyclerNew(scriptContext->GetRecycler(), JavascriptBigInt, scriptContext->GetLibrary()->GetBigIntTypeStatic());
@@ -286,6 +293,32 @@ namespace Js
286293
return newBigInt;
287294
}
288295

296+
Var JavascriptBigInt::Not(Var aRight)
297+
{
298+
JavascriptBigInt* rightBigInt = VarTo<JavascriptBigInt>(aRight);
299+
JavascriptBigInt* newBigInt = JavascriptBigInt::New(rightBigInt, rightBigInt->GetScriptContext());
300+
JavascriptBigInt::Negate(newBigInt);
301+
JavascriptBigInt * bigintOne = JavascriptBigInt::CreateOne(rightBigInt->GetScriptContext());
302+
return JavascriptBigInt::Sub(newBigInt, bigintOne);
303+
}
304+
305+
Var JavascriptBigInt::Negate(Var aRight)
306+
{
307+
JavascriptBigInt* rightBigInt = VarTo<JavascriptBigInt>(aRight);
308+
JavascriptBigInt* newBigInt = JavascriptBigInt::New(rightBigInt, rightBigInt->GetScriptContext());
309+
JavascriptBigInt::Negate(newBigInt);
310+
return newBigInt;
311+
}
312+
313+
void JavascriptBigInt::Negate(JavascriptBigInt * pbi)
314+
{
315+
if (JavascriptBigInt::IsZero(pbi))
316+
{
317+
return;
318+
}
319+
pbi->m_isNegative = !pbi->m_isNegative;
320+
}
321+
289322
// return low(a*b) and out high
290323
digit_t JavascriptBigInt::MulDigit(digit_t a, digit_t b, digit_t* resultHigh)
291324
{

lib/Runtime/Library/JavascriptBigInt.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@ namespace Js
4040
static Var Add(Var aLeft, Var aRight);
4141
static Var Sub(Var aLeft, Var aRight);
4242
static Var Decrement(Var aRight);
43+
static Var Not(Var aRight);
44+
static Var Negate(Var aRight);
4345

4446
inline BOOL isNegative() { return m_isNegative; }
4547

4648
static JavascriptBigInt * CreateZero(ScriptContext * scriptContext);
49+
static JavascriptBigInt * CreateOne(ScriptContext * scriptContext);
4750
static JavascriptBigInt * Create(const char16 * content, charcount_t cchUseLength, bool isNegative, ScriptContext * scriptContext);
4851
virtual RecyclableObject * CloneToScriptContext(ScriptContext* requestContext) override;
4952

@@ -71,8 +74,9 @@ namespace Js
7174
static bool IsZero(JavascriptBigInt * pbi);
7275
static void AbsoluteIncrement(JavascriptBigInt * pbi);
7376
static void AbsoluteDecrement(JavascriptBigInt * pbi);
74-
static void Increment(JavascriptBigInt * aValue);
77+
static void Increment(JavascriptBigInt * pbi);
7578
static void Decrement(JavascriptBigInt * pbi);
79+
static void Negate(JavascriptBigInt * pbi);
7680
static JavascriptBigInt * Add(JavascriptBigInt * pbi1, JavascriptBigInt * pbi2);
7781
static void AddAbsolute(JavascriptBigInt * pbi1, JavascriptBigInt * pbi2);
7882
static JavascriptBigInt * Sub(JavascriptBigInt * pbi1, JavascriptBigInt * pbi2);

lib/Runtime/Math/JavascriptMath.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ using namespace Js;
1313
return scriptContext->GetLibrary()->GetNegativeZero();
1414
}
1515

16+
if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
17+
{
18+
return JavascriptBigInt::Negate(aRight);
19+
}
20+
1621
double value = Negate_Helper(aRight, scriptContext);
1722
return JavascriptNumber::ToVarIntCheck(value, scriptContext);
1823
JIT_HELPER_END(Op_Negate_Full);
@@ -28,6 +33,11 @@ using namespace Js;
2833
return scriptContext->GetLibrary()->GetNegativeZero();
2934
}
3035

36+
if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
37+
{
38+
return JavascriptBigInt::Negate(aRight);
39+
}
40+
3141
double value = Negate_Helper(aRight, scriptContext);
3242
return JavascriptNumber::InPlaceNew(value, scriptContext, result);
3343
JIT_HELPER_END(Op_NegateInPlace);
@@ -39,6 +49,11 @@ using namespace Js;
3949
#if _M_IX86
4050
AssertMsg(!TaggedInt::Is(aRight), "Should be detected");
4151
#endif
52+
if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
53+
{
54+
return JavascriptBigInt::Not(aRight);
55+
}
56+
4257
int nValue = JavascriptConversion::ToInt32(aRight, scriptContext);
4358
return JavascriptNumber::ToVar(~nValue, scriptContext);
4459
JIT_HELPER_END(Op_Not_Full);
@@ -50,6 +65,11 @@ using namespace Js;
5065
JIT_HELPER_REENTRANT_HEADER(Op_NotInPlace);
5166
AssertMsg(!TaggedInt::Is(aRight), "Should be detected");
5267

68+
if (JavascriptOperators::GetTypeId(aRight) == TypeIds_BigInt)
69+
{
70+
return JavascriptBigInt::Not(aRight);
71+
}
72+
5373
int nValue = JavascriptConversion::ToInt32(aRight, scriptContext);
5474
return JavascriptNumber::ToVarInPlace(~nValue, scriptContext, result);
5575
JIT_HELPER_END(Op_NotInPlace);

test/BigInt/bitwise_not.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
7+
if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
8+
this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
9+
}
10+
11+
var tests = [
12+
{
13+
name: "BigInt literal",
14+
body: function () {
15+
var x = ~123n;
16+
assert.isTrue(x == -124n);
17+
}
18+
},
19+
{
20+
name: "Negative BigInt literal",
21+
body: function () {
22+
var x = ~-123n;
23+
assert.isTrue(x == 122n);
24+
}
25+
},
26+
{
27+
name: "0n",
28+
body: function () {
29+
var x = ~0n;
30+
assert.isTrue(x == -1n);
31+
}
32+
},
33+
{
34+
name: "BigInt Object",
35+
body: function () {
36+
var x = ~BigInt(12345n);
37+
var y = BigInt(-12346n);
38+
assert.isTrue(x == y);
39+
}
40+
},
41+
{
42+
name: "Out of 64 bit range",
43+
body: function () {
44+
var x = ~1234567890123456789012345678901234567890n;
45+
var y = -1234567890123456789012345678901234567891n;
46+
assert.isTrue(x == y);
47+
}
48+
},
49+
{
50+
name: "Very big",
51+
body: function () {
52+
var x = eval('1234567890'.repeat(20)+'0n');
53+
var y = -x-1n;
54+
var z = ~x;
55+
assert.isTrue(z == y);
56+
}
57+
},
58+
{
59+
name: "With assign",
60+
body: function () {
61+
var x = 3n;
62+
var y = x;
63+
assert.isTrue(x == 3n);
64+
assert.isTrue(y == 3n);
65+
y = ~x;
66+
assert.isTrue(x == 3n);
67+
assert.isTrue(y == -4n);
68+
}
69+
},
70+
];
71+
72+
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

test/BigInt/rlexe.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,10 @@
5454
<compile-flags>-args summary -endargs -ESBigInt</compile-flags>
5555
</default>
5656
</test>
57+
<test>
58+
<default>
59+
<files>bitwise_not.js</files>
60+
<compile-flags>-args summary -endargs -ESBigInt</compile-flags>
61+
</default>
62+
</test>
5763
</regress-exe>

0 commit comments

Comments
 (0)