@@ -12,14 +12,17 @@ namespace Js
1212 }
1313
1414 JavascriptBigInt * JavascriptBigInt::CreateZero (ScriptContext * scriptContext)
15+ {
16+ return JavascriptBigInt::CreateZeroWithLength (1 , scriptContext);
17+ }
18+
19+ JavascriptBigInt * JavascriptBigInt::CreateZeroWithLength (digit_t length, ScriptContext * scriptContext)
1520 {
1621 JavascriptBigInt * bigintNew = RecyclerNew (scriptContext->GetRecycler (), JavascriptBigInt, scriptContext->GetLibrary ()->GetBigIntTypeStatic ());
17- bigintNew->m_length = 1 ;
22+ bigintNew->m_length = length ;
1823 bigintNew->m_isNegative = false ;
19- bigintNew->m_maxLength = 1 ;
20- bigintNew->m_digits = RecyclerNewArrayLeaf (scriptContext->GetRecycler (), digit_t , bigintNew->m_length );
21- bigintNew->m_digits [0 ] = 0 ;
22-
24+ bigintNew->m_maxLength = length;
25+ bigintNew->m_digits = RecyclerNewArrayLeafZ (scriptContext->GetRecycler (), digit_t , bigintNew->m_length );
2326 return bigintNew;
2427 }
2528
@@ -32,11 +35,12 @@ namespace Js
3235
3336 JavascriptBigInt * JavascriptBigInt::New (JavascriptBigInt * pbi, ScriptContext * scriptContext)
3437 {
38+ Assert (pbi->m_maxLength >= pbi->m_length );
3539 JavascriptBigInt * bigintNew = RecyclerNew (scriptContext->GetRecycler (), JavascriptBigInt, scriptContext->GetLibrary ()->GetBigIntTypeStatic ());
3640 bigintNew->m_length = pbi->m_length ;
3741 bigintNew->m_maxLength = pbi->m_maxLength ;
3842 bigintNew->m_isNegative = pbi->m_isNegative ;
39- bigintNew->m_digits = RecyclerNewArrayLeaf (scriptContext->GetRecycler (), digit_t , pbi->m_length );
43+ bigintNew->m_digits = RecyclerNewArrayLeaf (scriptContext->GetRecycler (), digit_t , pbi->m_maxLength );
4044 js_memcpy_s (bigintNew->m_digits , bigintNew->m_length * sizeof (digit_t ), pbi->m_digits , bigintNew->m_length * sizeof (digit_t ));
4145
4246 return bigintNew;
@@ -151,23 +155,20 @@ namespace Js
151155
152156 digit_t digitMul = 1 ;
153157 digit_t digitAdd = 0 ;
154- bool check = true ;
155158 for (; pChar < pCharLimit; pChar++)
156159 {
157160 Assert (NumberUtilities::IsDigit (*pChar));
158161 if (digitMul == 1e9 )
159162 {
160- check = MulThenAdd (digitMul, digitAdd);
161- Assert (check);
163+ MulThenAdd (digitMul, digitAdd);
162164 digitMul = 1 ;
163165 digitAdd = 0 ;
164166 }
165167 digitMul *= 10 ;
166168 digitAdd = digitAdd * 10 + *pChar - ' 0' ;
167169 }
168170 Assert (1 < digitMul);
169- check = MulThenAdd (digitMul, digitAdd);
170- Assert (check);
171+ MulThenAdd (digitMul, digitAdd);
171172
172173 // make sure this is no negative zero
173174 if (m_length == 0 )
@@ -352,7 +353,7 @@ namespace Js
352353 return resultLow;
353354 }
354355
355- bool JavascriptBigInt::MulThenAdd (digit_t digitMul, digit_t digitAdd)
356+ void JavascriptBigInt::MulThenAdd (digit_t digitMul, digit_t digitAdd)
356357 {
357358 Assert (digitMul != 0 );
358359
@@ -377,7 +378,6 @@ namespace Js
377378 }
378379 m_digits[m_length++] = digitAdd;
379380 }
380- return true ;
381381 }
382382
383383 int JavascriptBigInt::Compare (JavascriptBigInt *pbi)
@@ -419,7 +419,9 @@ namespace Js
419419 for (index = m_length - 1 ; m_digits[index] == pbi->m_digits [index]; index--)
420420 {
421421 if (0 == index)
422+ {
422423 return 0 ;
424+ }
423425 }
424426 Assert (m_digits[index] != pbi->m_digits [index]);
425427
@@ -554,6 +556,72 @@ namespace Js
554556 }
555557 }
556558
559+ // return |pbi1| * |pbi2|
560+ JavascriptBigInt * JavascriptBigInt::MulAbsolute (JavascriptBigInt * pbi1, JavascriptBigInt * pbi2)
561+ {
562+ // Start with maximum length possible in pbi3
563+ digit_t length = pbi1->m_length + pbi2->m_length ;
564+ if (SIZE_MAX / sizeof (digit_t ) < length) // overflow
565+ {
566+ JavascriptError::ThrowRangeError (pbi1->GetScriptContext (), VBSERR_TypeMismatch, _u (" Multiply BigInt" ));
567+ }
568+ JavascriptBigInt * pbi3 = JavascriptBigInt::CreateZeroWithLength (length, pbi1->GetScriptContext ());
569+
570+ // Compute pbi3 = pbi1 * pbi2 as follow:
571+ // e.g. A1 A0 * B1 B0 = C3 C2 C1 C0
572+ // C0 = A0 * B0 (take the digit and carry)
573+ // C1 = carry + A0 * B1 + A1 * B0 (take the digit and carry)
574+ // C2 = carry + A1 * B1 (take the digit and carry)
575+ // C3 = carry
576+ digit_t carryDigit = 0 ;
577+ digit_t i3 = 0 ;
578+
579+ for (digit_t i1 = 0 ; i1 < pbi1->m_length ; i1++)
580+ {
581+ carryDigit = 0 ;
582+ for (digit_t i2 = 0 ; i2 < pbi2->m_length ; i2++)
583+ {
584+ i3 = i1 + i2;
585+ digit_t tempCarryDigit1 = 0 ;
586+ digit_t tempCarryDigit2 = 0 ;
587+ pbi3->m_digits [i3] = JavascriptBigInt::AddDigit (pbi3->m_digits [i3], carryDigit, &tempCarryDigit1);
588+ digit_t mulDigitResult = JavascriptBigInt::MulDigit (pbi1->m_digits [i1], pbi2->m_digits [i2], &carryDigit);
589+ pbi3->m_digits [i3] = JavascriptBigInt::AddDigit (pbi3->m_digits [i3], mulDigitResult, &tempCarryDigit2);
590+ digit_t overflow = 0 ;
591+ carryDigit = JavascriptBigInt::AddDigit (carryDigit, tempCarryDigit1, &overflow);
592+ Assert (overflow == 0 ); // [i1] * [i2] can not carry through [i1+i2+2]
593+ carryDigit = JavascriptBigInt::AddDigit (carryDigit, tempCarryDigit2, &overflow);
594+ Assert (overflow == 0 ); // [i1] * [i2] can not carry through [i1+i2+2]
595+ }
596+ if (carryDigit > 0 )
597+ {
598+ pbi3->m_digits [i3 + 1 ] = carryDigit;
599+ }
600+ }
601+
602+ // adjust length
603+ while ((pbi3->m_length > 0 ) && (pbi3->m_digits [pbi3->m_length - 1 ] == 0 ))
604+ {
605+ pbi3->m_length --;
606+ }
607+ Assert (pbi3->m_length > 0 );
608+ return pbi3;
609+ }
610+
611+ JavascriptBigInt * JavascriptBigInt::Mul (JavascriptBigInt * pbi1, JavascriptBigInt * pbi2)
612+ {
613+ if (JavascriptBigInt::IsZero (pbi1) || JavascriptBigInt::IsZero (pbi2))
614+ {
615+ return JavascriptBigInt::CreateZero (pbi1->GetScriptContext ());
616+ }
617+ JavascriptBigInt * result = JavascriptBigInt::MulAbsolute (pbi1, pbi2);
618+ if (pbi1->m_isNegative != pbi2->m_isNegative )
619+ {
620+ result->m_isNegative = true ;
621+ }
622+ return result;
623+ }
624+
557625 JavascriptBigInt * JavascriptBigInt::Add (JavascriptBigInt * pbi1, JavascriptBigInt * pbi2)
558626 {
559627 if (JavascriptBigInt::IsZero (pbi1))
@@ -607,4 +675,11 @@ namespace Js
607675 // TODO: Consider deferring creation of new instances until we need them
608676 }
609677
678+ Var JavascriptBigInt::Mul (Var aLeft, Var aRight)
679+ {
680+ JavascriptBigInt *leftBigInt = VarTo<JavascriptBigInt>(aLeft);
681+ JavascriptBigInt *rightBigInt = VarTo<JavascriptBigInt>(aRight);
682+ return JavascriptBigInt::Mul (leftBigInt, rightBigInt);
683+ }
684+
610685} // namespace Js
0 commit comments