Skip to content

Commit eeba684

Browse files
committed
[MERGE #5706 @duongnhn] Implement stage 3 proposal BigInt (init and comparison with signed BigInt)
Merge pull request #5706 from duongnhn:user/duongn/bigint The BigInt proposal (https://github.com/tc39/proposal-bigint) is in stage 3. With this PR, we can initialize signed BigInt literal or use BigInt constructor and do comparisons among BigInt types. This is missing a bunch of things but the code change keep growing so I would like to lay some foundation and move forward. What I have done: - (Flag) ESBigInt is set to false by default - (Scan and Parser) token and parse node for BigInt literal - (Library) Create JavascriptBigInt and JavascriptBigIntObject with basic functions. - (JavascriptBigInt) Convert from decimal digit chars to an array of uint32 digits (where we store BigInt) and compare between 2 BigInts - (Test) create test for init, comparisons, global BigInt object. TODOs: - resize memory dynamically. Currently it uses a fixed space for BigInt which is against arbitrary precision. - other operators and conversion. - tagged bigint - JIT - etc Part of #5440
2 parents 73a097d + c426eab commit eeba684

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+5439
-4703
lines changed

bin/NativeTests/BigUIntTest.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace Js
2626
}
2727

2828
template <typename EncodedChar>
29-
double Js::NumberUtilities::StrToDbl(const EncodedChar *, const EncodedChar **, bool& )
29+
double Js::NumberUtilities::StrToDbl(const EncodedChar *, const EncodedChar **, LikelyNumberType& , bool)
3030
{
3131
Assert(false);
3232
return 0.0;// don't care

lib/Common/Common/NumberUtilities.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,8 @@ using namespace Js;
684684
double NumberUtilities::StrToDbl(const EncodedChar * psz, const EncodedChar **ppchLim, Js::ScriptContext *const scriptContext)
685685
{
686686
Assert(scriptContext);
687-
bool likelyInt = true;
688-
return Js::NumberUtilities::StrToDbl<EncodedChar>(psz, ppchLim, likelyInt);
687+
LikelyNumberType likelyType = LikelyNumberType::Int;
688+
return Js::NumberUtilities::StrToDbl<EncodedChar>(psz, ppchLim, likelyType);
689689
}
690690

691691
template double NumberUtilities::StrToDbl<char16>(const char16 * psz, const char16 **ppchLim, Js::ScriptContext *const scriptContext);

lib/Common/Common/NumberUtilities.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
//-------------------------------------------------------------------------------------------------------
55
#pragma once
66

7+
enum class LikelyNumberType
8+
{
9+
Double,
10+
Int,
11+
BigInt,
12+
};
13+
14+
715
namespace Js
816
{
917
class NumberConstants : public NumberConstantsBase
@@ -217,7 +225,7 @@ namespace Js
217225

218226
// Implemented in lib\parser\common. Should move to lib\common
219227
template<typename EncodedChar>
220-
static double StrToDbl(const EncodedChar *psz, const EncodedChar **ppchLim, bool& likelyInt);
228+
static double StrToDbl(const EncodedChar *psz, const EncodedChar **ppchLim, LikelyNumberType& likelyType, bool isESBigIntEnabled = false);
221229

222230
static BOOL FDblToStr(double dbl, __out_ecount(nDstBufSize) char16 *psz, int nDstBufSize);
223231
static int FDblToStr(double dbl, NumberUtilities::FormatType ft, int nDigits, __out_ecount(cchDst) char16 *pchDst, int cchDst);

lib/Common/Common/NumberUtilities_strtod.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -893,13 +893,13 @@ static double AdjustDbl(double dbl, const EncodedChar *prgch, int32 cch, int32 l
893893
String to Double.
894894
***************************************************************************/
895895
template <typename EncodedChar>
896-
double Js::NumberUtilities::StrToDbl( const EncodedChar *psz, const EncodedChar **ppchLim, bool& likelyInt )
896+
double Js::NumberUtilities::StrToDbl( const EncodedChar *psz, const EncodedChar **ppchLim, LikelyNumberType& likelyNumberType, bool isBigIntEnabled)
897897
{
898898
uint32 lu;
899899
BIGNUM num;
900900
BIGNUM numHi;
901901
BIGNUM numLo;
902-
double dbl;
902+
double dbl = 0;
903903
double dblLo;
904904
#if DBG
905905
bool canUseLowPrec = false;
@@ -990,12 +990,19 @@ double Js::NumberUtilities::StrToDbl( const EncodedChar *psz, const EncodedChar
990990
case 'E':
991991
case 'e':
992992
goto LGetExp;
993+
case 'n':
994+
if (isBigIntEnabled)
995+
{
996+
goto LBigInt;
997+
}
998+
default:
999+
likelyNumberType = LikelyNumberType::Int;
9931000
}
9941001
goto LEnd;
9951002

9961003
LGetRight:
9971004
Assert(*pch == '.');
998-
likelyInt = false;
1005+
likelyNumberType = LikelyNumberType::Double;
9991006
pch++;
10001007
if (NULL == pchMinDig)
10011008
{
@@ -1043,6 +1050,13 @@ double Js::NumberUtilities::StrToDbl( const EncodedChar *psz, const EncodedChar
10431050
if (lwExp > 100000000)
10441051
lwExp = 100000000;
10451052
}
1053+
goto LEnd;
1054+
1055+
LBigInt:
1056+
pch++;
1057+
likelyNumberType = LikelyNumberType::BigInt;
1058+
*ppchLim = pch;
1059+
goto LDone;
10461060

10471061
LEnd:
10481062
*ppchLim = pch;
@@ -1256,8 +1270,8 @@ double Js::NumberUtilities::StrToDbl( const EncodedChar *psz, const EncodedChar
12561270
return dbl;
12571271
}
12581272

1259-
template double Js::NumberUtilities::StrToDbl<char16>( const char16 * psz, const char16 **ppchLim, bool& likelyInt );
1260-
template double Js::NumberUtilities::StrToDbl<utf8char_t>(const utf8char_t * psz, const utf8char_t **ppchLim, bool& likelyInt);
1273+
template double Js::NumberUtilities::StrToDbl<char16>( const char16 * psz, const char16 **ppchLim, LikelyNumberType& likelyInt, bool isBigIntEnabled );
1274+
template double Js::NumberUtilities::StrToDbl<utf8char_t>(const utf8char_t * psz, const utf8char_t **ppchLim, LikelyNumberType& likelyInt, bool isBigIntEnabled );
12611275

12621276
/***************************************************************************
12631277
Uses big integer arithmetic to get the sequence of digits.
@@ -2439,8 +2453,8 @@ BOOL Js::NumberUtilities::FNonZeroFiniteDblToStr(double dbl, __out_ecount(cchDst
24392453
{
24402454
if (FormatDigits(rgb, pbLim, wExp10, pchDst, cchDst))
24412455
{
2442-
bool likelyInt = true;
2443-
dblT = StrToDbl<char16>(pchDst, &pch,likelyInt);
2456+
LikelyNumberType likelyInt = LikelyNumberType::Int;
2457+
dblT = StrToDbl<char16>(pchDst, &pch, likelyInt);
24442458
Assert(0 == *pch);
24452459
Assert(dblT == dbl);
24462460
}
@@ -2465,7 +2479,7 @@ BOOL Js::NumberUtilities::FNonZeroFiniteDblToStr(double dbl, __out_ecount(cchDst
24652479
}
24662480

24672481
#if DBG
2468-
bool likelyInt = true;
2482+
LikelyNumberType likelyInt = LikelyNumberType::Int;
24692483
dblT = StrToDbl<char16>(pchDst, &pch, likelyInt);
24702484
Assert(0 == *pch);
24712485
Assert(dblT == dbl);

lib/Common/ConfigFlagsList.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ PHASE(All)
650650
#define DEFAULT_CONFIG_ES6Unscopables (true)
651651
#define DEFAULT_CONFIG_ES6RegExSticky (true)
652652
#define DEFAULT_CONFIG_ES2018RegExDotAll (true)
653+
#define DEFAULT_CONFIG_ESBigInt (false)
653654
#ifdef COMPILE_DISABLE_ES6RegExPrototypeProperties
654655
// If ES6RegExPrototypeProperties needs to be disabled by compile flag, DEFAULT_CONFIG_ES6RegExPrototypeProperties should be false
655656
#define DEFAULT_CONFIG_ES6RegExPrototypeProperties (false)
@@ -1083,6 +1084,7 @@ FLAGNR(Boolean, EntryPointInfoRpcData , "Keep encoded rpc buffer for jitted func
10831084

10841085
FLAGNR(Boolean, LdChakraLib , "Access to the Chakra internal library with the __chakraLibrary keyword", DEFAULT_CONFIG_LdChakraLib)
10851086
FLAGNR(Boolean, TestChakraLib , "Access to the Chakra internal library with the __chakraLibrary keyword without global access restriction", DEFAULT_CONFIG_TestChakraLib)
1087+
10861088
// ES6 (BLUE+1) features/flags
10871089

10881090
// Master ES6 flag to enable STABLE ES6 features/flags
@@ -1178,6 +1180,9 @@ FLAGNR(Boolean, WinRTDelegateInterfaces , "Treat WinRT Delegates as Interfaces w
11781180
FLAGR(Boolean, WinRTAdaptiveApps , "Enable the adaptive apps feature, allowing for variable projection." , DEFAULT_CONFIG_WinRTAdaptiveApps)
11791181
#endif
11801182

1183+
// ES BigInt flag
1184+
FLAGR(Boolean, ESBigInt, "Enable ESBigInt flag", DEFAULT_CONFIG_ESBigInt)
1185+
11811186
// This flag to be removed once JITing generator functions is stable
11821187
FLAGNR(Boolean, JitES6Generators , "Enable JITing of ES6 generators", false)
11831188

lib/Parser/Parse.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,15 @@ ParseNodeStr * Parser::CreateStrNode(IdentPtr pid)
10521052
return pnode;
10531053
}
10541054

1055+
ParseNodeBigInt * Parser::CreateBigIntNode(IdentPtr pid)
1056+
{
1057+
Assert(!this->m_deferringAST);
1058+
ParseNodeBigInt * pnode = Anew(&m_nodeAllocator, ParseNodeBigInt, this->GetScanner()->IchMinTok(), this->GetScanner()->IchLimTok(), pid);
1059+
pnode->isNegative = false;
1060+
AddAstSize(sizeof(ParseNodeBigInt));
1061+
return pnode;
1062+
}
1063+
10551064
ParseNodeName * Parser::CreateNameNode(IdentPtr pid)
10561065
{
10571066
ParseNodeName * pnode = Anew(&m_nodeAllocator, ParseNodeName, this->GetScanner()->IchMinTok(), this->GetScanner()->IchLimTok(), pid);
@@ -3344,6 +3353,20 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
33443353
this->GetScanner()->Scan();
33453354
break;
33463355

3356+
case tkBigIntCon:
3357+
if (IsStrictMode() && this->GetScanner()->IsOctOrLeadingZeroOnLastTKNumber())
3358+
{
3359+
Error(ERRES5NoOctal);
3360+
}
3361+
3362+
if (buildAST)
3363+
{
3364+
pnode = CreateBigIntNode(m_token.GetBigInt());
3365+
}
3366+
fCanAssign = FALSE;
3367+
this->GetScanner()->Scan();
3368+
break;
3369+
33473370
case tkFltCon:
33483371
if (IsStrictMode() && this->GetScanner()->IsOctOrLeadingZeroOnLastTKNumber())
33493372
{
@@ -8786,15 +8809,20 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
87868809
}
87878810
else if (nop == knopNeg &&
87888811
((pnodeT->nop == knopInt && pnodeT->AsParseNodeInt()->lw != 0) ||
8789-
(pnodeT->nop == knopFlt && (pnodeT->AsParseNodeFloat()->dbl != 0 || this->m_InAsmMode))))
8812+
(pnodeT->nop == knopFlt && (pnodeT->AsParseNodeFloat()->dbl != 0 || this->m_InAsmMode)) ||
8813+
(pnodeT->nop == knopBigInt)))
87908814
{
87918815
// Fold a unary '-' on a number into the value of the number itself.
87928816
pnode = pnodeT;
87938817
if (pnode->nop == knopInt)
87948818
{
87958819
pnode->AsParseNodeInt()->lw = -pnode->AsParseNodeInt()->lw;
87968820
}
8797-
else
8821+
else if (pnode->nop == knopBigInt)
8822+
{
8823+
pnode->AsParseNodeBigInt()->isNegative = true;
8824+
}
8825+
else
87988826
{
87998827
pnode->AsParseNodeFloat()->dbl = -pnode->AsParseNodeFloat()->dbl;
88008828
}
@@ -9160,6 +9188,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
91609188
{
91619189
case knopName:
91629190
case knopInt:
9191+
case knopBigInt:
91639192
case knopFlt:
91649193
case knopStr:
91659194
case knopRegExp:
@@ -12271,6 +12300,9 @@ ParseNode* Parser::CopyPnode(ParseNode *pnode) {
1227112300
}
1227212301
//PTNODE(knopInt , "int const" ,None ,Int ,fnopLeaf|fnopConst)
1227312302
case knopInt:
12303+
return pnode;
12304+
//PTNODE(knopBigInt , "bigint const" ,None ,BigInt ,fnopLeaf|fnopConst)
12305+
case knopBigInt:
1227412306
return pnode;
1227512307
//PTNODE(knopFlt , "flt const" ,None ,Flt ,fnopLeaf|fnopConst)
1227612308
case knopFlt:
@@ -13348,6 +13380,11 @@ void PrintPnodeWIndent(ParseNode *pnode, int indentAmt) {
1334813380
Indent(indentAmt);
1334913381
Output::Print(_u("%d\n"), pnode->AsParseNodeInt()->lw);
1335013382
break;
13383+
//PTNODE(knopInt , "int const" ,None ,Int ,fnopLeaf|fnopConst)
13384+
case knopBigInt:
13385+
Indent(indentAmt);
13386+
Output::Print(_u("%s%s\n"), pnode->AsParseNodeBigInt()->isNegative? "-" : "", pnode->AsParseNodeBigInt()->pid->Psz());
13387+
break;
1335113388
//PTNODE(knopFlt , "flt const" ,None ,Flt ,fnopLeaf|fnopConst)
1335213389
case knopFlt:
1335313390
Indent(indentAmt);

lib/Parser/Parse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ class Parser
378378

379379
ParseNodeInt * CreateIntNode(int32 lw);
380380
ParseNodeStr * CreateStrNode(IdentPtr pid);
381+
ParseNodeBigInt * CreateBigIntNode(IdentPtr pid);
381382
ParseNodeName * CreateNameNode(IdentPtr pid);
382383
ParseNodeName * CreateNameNode(IdentPtr pid, PidRefStack * ref, charcount_t ichMin, charcount_t ichLim);
383384
ParseNodeSpecialName * CreateSpecialNameNode(IdentPtr pid, PidRefStack * ref, charcount_t ichMin, charcount_t ichLim);

lib/Parser/Scan.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -587,12 +587,12 @@ IdentPtr Scanner<EncodingPolicy>::PidOfIdentiferAt(EncodedCharPtr p, EncodedChar
587587
}
588588

589589
template <typename EncodingPolicy>
590-
typename Scanner<EncodingPolicy>::EncodedCharPtr Scanner<EncodingPolicy>::FScanNumber(EncodedCharPtr p, double *pdbl, bool& likelyInt, size_t savedMultiUnits)
590+
typename Scanner<EncodingPolicy>::EncodedCharPtr Scanner<EncodingPolicy>::FScanNumber(EncodedCharPtr p, double *pdbl, LikelyNumberType& likelyType, size_t savedMultiUnits)
591591
{
592592
EncodedCharPtr last = m_pchLast;
593593
EncodedCharPtr pchT = nullptr;
594594
bool baseSpecified = false;
595-
likelyInt = true;
595+
likelyType = LikelyNumberType::Int;
596596
// Reset
597597
m_OctOrLeadingZeroOnLastTKNumber = false;
598598

@@ -617,7 +617,8 @@ typename Scanner<EncodingPolicy>::EncodedCharPtr Scanner<EncodingPolicy>::FScanN
617617
case '.':
618618
case 'e':
619619
case 'E':
620-
likelyInt = false;
620+
case 'n':
621+
likelyType = LikelyNumberType::Double;
621622
// Floating point
622623
goto LFloat;
623624

@@ -668,8 +669,12 @@ typename Scanner<EncodingPolicy>::EncodedCharPtr Scanner<EncodingPolicy>::FScanN
668669
else
669670
{
670671
LFloat:
671-
*pdbl = Js::NumberUtilities::StrToDbl(p, &pchT, likelyInt);
672+
*pdbl = Js::NumberUtilities::StrToDbl(p, &pchT, likelyType, m_scriptContext->GetConfig()->IsESBigIntEnabled());
672673
Assert(pchT == p || !Js::NumberUtilities::IsNan(*pdbl));
674+
if (likelyType == LikelyNumberType::BigInt)
675+
{
676+
Assert(*pdbl == 0);
677+
}
673678
// fall through to LIdCheck
674679
}
675680

@@ -1723,28 +1728,36 @@ tokens Scanner<EncodingPolicy>::ScanCore(bool identifyKwds)
17231728
Assert(chType == _C_DIG || chType == _C_DOT);
17241729
p = m_pchMinTok;
17251730
this->RestoreMultiUnits(m_cMinTokMultiUnits);
1726-
bool likelyInt = true;
1727-
pchT = FScanNumber(p, &dbl, likelyInt, savedMultiUnits);
1731+
LikelyNumberType likelyType = LikelyNumberType::Int;
1732+
pchT = FScanNumber(p, &dbl, likelyType, savedMultiUnits);
17281733
if (p == pchT)
17291734
{
17301735
this->RestoreMultiUnits(savedMultiUnits);
17311736
Assert(this->PeekFirst(p, last) != '.');
17321737
Error(ERRbadNumber);
17331738
}
17341739
Assert(!Js::NumberUtilities::IsNan(dbl));
1735-
1740+
if (likelyType == LikelyNumberType::BigInt)
1741+
{
1742+
Assert(m_scriptContext->GetConfig()->IsESBigIntEnabled());
1743+
AssertOrFailFast(pchT - p < UINT_MAX);
1744+
token = tkBigIntCon;
1745+
m_ptoken->SetBigInt(this->GetHashTbl()->PidHashNameLen(p, pchT, (uint32) (pchT - p)));
1746+
p = pchT;
1747+
break;
1748+
}
17361749
p = pchT;
17371750

17381751
int32 value;
1739-
if (likelyInt && Js::NumberUtilities::FDblIsInt32(dbl, &value))
1752+
if ((likelyType == LikelyNumberType::Int) && Js::NumberUtilities::FDblIsInt32(dbl, &value))
17401753
{
17411754
m_ptoken->SetLong(value);
17421755
token = tkIntCon;
17431756
}
17441757
else
17451758
{
17461759
token = tkFltCon;
1747-
m_ptoken->SetDouble(dbl, likelyInt);
1760+
m_ptoken->SetDouble(dbl, likelyType == LikelyNumberType::Int);
17481761
}
17491762

17501763
break;

lib/Parser/Scan.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ struct Token
5858
Assert(tk == tkStrCon || tk == tkStrTmplBasic || tk == tkStrTmplBegin || tk == tkStrTmplMid || tk == tkStrTmplEnd);
5959
return u.pid;
6060
}
61+
6162
IdentPtr GetIdentifier(HashTbl * hashTbl)
6263
{
6364
Assert(IsIdentifier() || IsReservedWord());
@@ -74,6 +75,12 @@ struct Token
7475
return u.lw;
7576
}
7677

78+
IdentPtr GetBigInt() const
79+
{
80+
Assert(tk == tkBigIntCon);
81+
return u.pid;
82+
}
83+
7784
double GetDouble() const
7885
{
7986
Assert(tk == tkFltCon);
@@ -138,6 +145,12 @@ struct Token
138145
this->u.maybeInt = maybeInt;
139146
}
140147

148+
void SetBigInt(IdentPtr pid)
149+
{
150+
this->u.pid = pid;
151+
this->u.pchMin = nullptr;
152+
}
153+
141154
tokens SetRegex(UnifiedRegex::RegexPattern *const pattern, Parser *const parser);
142155
};
143156

@@ -788,7 +801,7 @@ class Scanner : public IScanner, public EncodingPolicy
788801
tokens SkipComment(EncodedCharPtr *pp, /* out */ bool* containTypeDef);
789802
tokens ScanRegExpConstant(ArenaAllocator* alloc);
790803
tokens ScanRegExpConstantNoAST(ArenaAllocator* alloc);
791-
EncodedCharPtr FScanNumber(EncodedCharPtr p, double *pdbl, bool& likelyInt, size_t savedMultiUnits);
804+
EncodedCharPtr FScanNumber(EncodedCharPtr p, double *pdbl, LikelyNumberType& likelyInt, size_t savedMultiUnits);
792805
IdentPtr PidOfIdentiferAt(EncodedCharPtr p, EncodedCharPtr last, bool fHadEscape, bool fHasMultiChar);
793806
IdentPtr PidOfIdentiferAt(EncodedCharPtr p, EncodedCharPtr last);
794807
uint32 UnescapeToTempBuf(EncodedCharPtr p, EncodedCharPtr last);

lib/Parser/ptlist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ PTNODE(knopNone , "<none>" , Nop , None , fnopNone
2323
***************************************************************************/
2424
PTNODE(knopName , "name" , Nop , Name , fnopLeaf|fnopAllowDefer, "NameExpr" )
2525
PTNODE(knopInt , "int const" , Nop , Int , fnopLeaf|fnopConst , "NumberLit" )
26+
PTNODE(knopBigInt , "bigint const" , Nop , BigInt , fnopLeaf|fnopConst , "BigIntLit" )
2627
PTNODE(knopImport , "import" , Nop , None , fnopLeaf , "ImportExpr" )
2728
PTNODE(knopFlt , "flt const" , Nop , Float , fnopLeaf|fnopConst , "NumberLit" )
2829
PTNODE(knopStr , "str const" , Nop , Str , fnopLeaf|fnopConst , "StringLit" )

0 commit comments

Comments
 (0)