• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/js_bigint.h"
17 
18 #include "ecmascript/base/bit_helper.h"
19 #include "ecmascript/js_tagged_value-inl.h"
20 #include "ecmascript/js_tagged_number.h"
21 
22 namespace panda::ecmascript {
23 class ObjectFactory;
24 constexpr char dp[] = "0123456789abcdefghijklmnopqrstuvwxyz";
CharToInt(char c)25 static int CharToInt(char c)
26 {
27     uint32_t res = 0;
28     if (c >= '0' && c <= '9') {
29         res = c - '0';
30     } else if (c >= 'A' && c <= 'Z') {
31         res = c - 'A' + 10; // 10:res must Greater than 10.
32     } else if (c >= 'a' && c <= 'z') {
33         res = c - 'a' + 10; // 10:res must Greater than 10
34     }
35     return static_cast<int>(res);
36 }
37 
Division(CString & num,uint32_t conversionToRadix,uint32_t currentRadix,uint32_t & remain)38 static void Division(CString &num, uint32_t conversionToRadix, uint32_t currentRadix, uint32_t &remain)
39 {
40     ASSERT(conversionToRadix != 0);
41     uint32_t temp = 0;
42     remain = 0;
43     for (size_t i = 0; i < num.size(); i++) {
44         temp = (currentRadix * remain + static_cast<uint32_t>(CharToInt(num[i])));
45         num[i] = dp[temp / conversionToRadix];
46         remain = temp % conversionToRadix;
47     }
48     size_t count = 0;
49     while (count < num.size() && num[count] == '0') {
50         count++;
51     }
52     num = num.substr(count);
53 }
54 
Conversion(const CString & num,uint32_t conversionToRadix,uint32_t currentRadix)55 CString BigIntHelper::Conversion(const CString &num, uint32_t conversionToRadix, uint32_t currentRadix)
56 {
57     ASSERT(conversionToRadix != 0);
58     CString newNum = num;
59     CString res;
60     uint32_t remain = 0;
61     while (newNum.size() != 0) {
62         Division(newNum, conversionToRadix, currentRadix, remain);
63         res = dp[remain] + res;
64     }
65     return res;
66 }
67 
GetUint64MaxBigint(JSThread * thread)68 JSHandle<BigInt> BigInt::GetUint64MaxBigint(JSThread *thread)
69 {
70     JSHandle<BigInt> bigint = CreateBigint(thread, 3);
71     bigint->SetDigit(0, 0);
72     bigint->SetDigit(1, 0);
73     bigint->SetDigit(2, 1);
74     return bigint;
75 }
76 
GetInt64MaxBigint(JSThread * thread)77 JSHandle<BigInt> BigInt::GetInt64MaxBigint(JSThread *thread)
78 {
79     JSHandle<BigInt> bigint = CreateBigint(thread, 2);
80     bigint->SetDigit(0, 0);
81     bigint->SetDigit(1, 0x80000000); // 0x80000000:Int MAX
82     return bigint;
83 }
84 
SetBigInt(JSThread * thread,const CString & numStr,uint32_t currentRadix)85 JSHandle<BigInt> BigIntHelper::SetBigInt(JSThread *thread, const CString &numStr, uint32_t currentRadix)
86 {
87     int flag = 0;
88     if (numStr[0] == '-') {
89         flag = 1;
90     }
91 
92     CString binaryStr = "";
93     if (currentRadix != BigInt::BINARY) {
94         binaryStr = Conversion(numStr.substr(flag), BigInt::BINARY, currentRadix);
95     } else {
96         binaryStr = numStr.substr(flag);
97     }
98 
99     JSHandle<BigInt> bigint;
100     size_t binaryStrLen = binaryStr.size();
101     size_t len = binaryStrLen / BigInt::DATEBITS;
102     size_t mod = binaryStrLen % BigInt::DATEBITS;
103     int index = 0;
104     if (mod == 0) {
105         index = static_cast<int>(len - 1);
106         bigint = BigInt::CreateBigint(thread, len);
107     } else {
108         len++;
109         index = static_cast<int>(len - 1);
110         bigint = BigInt::CreateBigint(thread, len);
111         uint32_t val = 0;
112         for (size_t i = 0; i < mod; ++i) {
113             val <<= 1;
114             val |= static_cast<uint32_t>(binaryStr[i] - '0');
115         }
116         bigint->SetDigit(index, val);
117         index--;
118     }
119     if (flag == 1) {
120         bigint->SetSign(true);
121     }
122     size_t i = mod;
123     while (i < binaryStrLen) {
124         uint32_t val = 0;
125         for (size_t j = 0; j < BigInt::DATEBITS && i < binaryStrLen; ++j, ++i) {
126             val <<= 1;
127             val |= static_cast<uint32_t>(binaryStr[i] - '0');
128         }
129         bigint->SetDigit(index, val);
130         index--;
131     }
132     return BigIntHelper::RightTruncate(thread, bigint);
133 }
134 
RightTruncate(JSThread * thread,JSHandle<BigInt> x)135 JSHandle<BigInt> BigIntHelper::RightTruncate(JSThread *thread, JSHandle<BigInt> x)
136 {
137     int len  = static_cast<int>(x->GetLength());
138     ASSERT(len != 0);
139     if (len == 1 && x->GetDigit(0) == 0) {
140         x->SetSign(false);
141         return x;
142     }
143     int index = len - 1;
144     if (x->GetDigit(index) != 0) {
145         return x;
146     }
147     while (index >= 0) {
148         if (x->GetDigit(index) != 0) {
149             break;
150         }
151         index--;
152     }
153 
154     if (index == -1) {
155         return BigInt::Int32ToBigInt(thread, 0);
156     } else {
157         ASSERT(index >= 0);
158         return BigInt::Copy(thread, x, index + 1);
159     }
160 }
161 
GetBinary(const BigInt * bigint)162 CString BigIntHelper::GetBinary(const BigInt *bigint)
163 {
164     ASSERT(bigint != nullptr);
165     int index = 0;
166     int len = static_cast<int>(bigint->GetLength());
167     int strLen = BigInt::DATEBITS * len;
168     CString res(strLen, '0');
169     int strIndex = strLen - 1;
170     while (index < len) {
171         int bityLen = BigInt::DATEBITS;
172         uint32_t val = bigint->GetDigit(index);
173         while (bityLen--) {
174             res[strIndex--] = (val & 1) + '0';
175             val = val >> 1;
176         }
177         index++;
178     }
179     DeZero(res);
180     return res;
181 }
182 
CreateBigint(JSThread * thread,uint32_t length)183 JSHandle<BigInt> BigInt::CreateBigint(JSThread *thread, uint32_t length)
184 {
185     ASSERT(length < MAXSIZE);
186     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
187     JSHandle<BigInt> bigint = factory->NewBigInt(length);
188     return bigint;
189 }
190 
191 // 6.1.6.2.13
Equal(const JSTaggedValue & x,const JSTaggedValue & y)192 bool BigInt::Equal(const JSTaggedValue &x, const JSTaggedValue &y)
193 {
194     BigInt* xVal = BigInt::Cast(x.GetTaggedObject());
195     BigInt* yVal = BigInt::Cast(y.GetTaggedObject());
196     return Equal(xVal, yVal);
197 }
198 
Equal(const BigInt * x,const BigInt * y)199 bool BigInt::Equal(const BigInt *x, const BigInt *y)
200 {
201     ASSERT(x != nullptr);
202     ASSERT(y != nullptr);
203     if (x->GetSign() != y->GetSign() || x->GetLength() != y->GetLength()) {
204         return false;
205     }
206     for (uint32_t i = 0; i < x->GetLength(); ++i) {
207         if (x->GetDigit(i) != y->GetDigit(i)) {
208             return false;
209         }
210     }
211     return true;
212 }
213 
214 // 6.1.6.2.14
SameValue(const JSTaggedValue & x,const JSTaggedValue & y)215 bool BigInt::SameValue(const JSTaggedValue &x, const JSTaggedValue &y)
216 {
217     return Equal(x, y);
218 }
219 
220 // 6.1.6.2.15
SameValueZero(const JSTaggedValue & x,const JSTaggedValue & y)221 bool BigInt::SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y)
222 {
223     return Equal(x, y);
224 }
225 
BitwiseOp(JSThread * thread,Operate op,JSHandle<BigInt> x,JSHandle<BigInt> y)226 JSHandle<BigInt> BigInt::BitwiseOp(JSThread *thread, Operate op, JSHandle<BigInt> x, JSHandle<BigInt> y)
227 {
228     uint32_t maxLen = 0;
229     uint32_t minLen = 0;
230     uint32_t xlen = x->GetLength();
231     uint32_t ylen = y->GetLength();
232     if (xlen > ylen) {
233         maxLen = xlen;
234         minLen = ylen;
235     } else {
236         maxLen = ylen;
237         minLen = xlen;
238     }
239     JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, maxLen);
240     for (size_t i = 0; i < minLen; ++i) {
241         if (op == Operate::OR) {
242             bigint->SetDigit(i, x->GetDigit(i) | y->GetDigit(i));
243         } else if (op == Operate::AND) {
244             bigint->SetDigit(i, x->GetDigit(i) & y->GetDigit(i));
245         } else {
246             ASSERT(op == Operate::XOR);
247             bigint->SetDigit(i, x->GetDigit(i) ^ y->GetDigit(i));
248         }
249     }
250     if (op == Operate::OR || op == Operate::XOR) {
251         if (xlen > ylen) {
252             for (size_t i = ylen; i < xlen; ++i) {
253                 bigint->SetDigit(i, x->GetDigit(i));
254             }
255         } else if (ylen > xlen) {
256             for (size_t i = xlen; i < ylen; ++i) {
257                 bigint->SetDigit(i, y->GetDigit(i));
258             }
259         }
260     }
261     return BigIntHelper::RightTruncate(thread, bigint);
262 }
263 
OneIsNegativeAND(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)264 JSHandle<BigInt> OneIsNegativeAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
265 {
266     JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength());
267     uint32_t xLength = x->GetLength();
268     uint32_t yLength = yVal->GetLength();
269     uint32_t minLen = xLength;
270     if (xLength > yLength) {
271         minLen = yLength;
272     }
273     JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, xLength);
274     uint32_t i = 0;
275     while (i < minLen) {
276         uint32_t res = x->GetDigit(i) & ~(yVal->GetDigit(i));
277         newBigint->SetDigit(i, res);
278         ++i;
279     }
280     while (i < xLength) {
281         newBigint->SetDigit(i, x->GetDigit(i));
282         ++i;
283     }
284     return BigIntHelper::RightTruncate(thread, newBigint);
285 }
286 
287 // 6.1.6.2.20 BigInt::bitwiseAND ( x, y )
BitwiseAND(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)288 JSHandle<BigInt> BigInt::BitwiseAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
289 {
290     if (x->GetSign() && y->GetSign()) {
291         // (-x) & (-y) == -(((x-1) | (y-1)) + 1)
292         JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, x->GetLength());
293         JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, y->GetLength());
294         JSHandle<BigInt> temp = BitwiseOp(thread, Operate::OR, xVal, yVal);
295         JSHandle<BigInt> res = BitwiseAddOne(thread, temp);
296         return res;
297     }
298     if (x->GetSign() != y->GetSign()) {
299         // x & (-y) == x & ~(y-1)
300         if (!x->GetSign()) {
301             return OneIsNegativeAND(thread, x, y);
302         } else {
303             return OneIsNegativeAND(thread, y, x);
304         }
305     }
306     return BitwiseOp(thread, Operate::AND, x, y);
307 }
308 
OneIsNegativeXOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)309 JSHandle<BigInt> OneIsNegativeXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
310 {
311     JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength());
312     JSHandle<BigInt> temp = BigInt::BitwiseOp(thread, Operate::XOR, x, yVal);
313     JSHandle<BigInt> res = BigInt::BitwiseAddOne(thread, temp);
314     return res;
315 }
316 
317 // 6.1.6.2.21 BigInt::bitwiseOR ( x, y )
BitwiseXOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)318 JSHandle<BigInt> BigInt::BitwiseXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
319 {
320     if (x->GetSign() && y->GetSign()) {
321         // (-x) ^ (-y) == (x-1) ^ (y-1)
322         JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, x->GetLength());
323         JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, y->GetLength());
324         return BitwiseOp(thread, Operate::XOR, xVal, yVal);
325     }
326     if (x->GetSign() != y->GetSign()) {
327         // x ^ (-y) == -((x ^ (y-1)) + 1)
328         if (!x->GetSign()) {
329             return OneIsNegativeXOR(thread, x, y);
330         } else {
331             return OneIsNegativeXOR(thread, y, x);
332         }
333     }
334     return BitwiseOp(thread, Operate::XOR, x, y);
335 }
336 
BitwiseSubOne(JSThread * thread,JSHandle<BigInt> bigint,uint32_t maxLen)337 JSHandle<BigInt> BigInt::BitwiseSubOne(JSThread *thread, JSHandle<BigInt> bigint, uint32_t maxLen)
338 {
339     ASSERT(!bigint->IsZero());
340     ASSERT(maxLen >= bigint->GetLength());
341 
342     JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, maxLen);
343 
344     uint32_t bigintLen = bigint->GetLength();
345     uint32_t carry = 1;
346     for (uint32_t i = 0; i < bigintLen; i++) {
347         uint32_t bigintCarry = 0;
348         newBigint->SetDigit(i, BigIntHelper::SubHelper(bigint->GetDigit(i), carry, bigintCarry));
349         carry = bigintCarry;
350     }
351     ASSERT(!carry);
352     return BigIntHelper::RightTruncate(thread, newBigint);
353 }
354 
BitwiseAddOne(JSThread * thread,JSHandle<BigInt> bigint)355 JSHandle<BigInt> BigInt::BitwiseAddOne(JSThread *thread, JSHandle<BigInt> bigint)
356 {
357     uint32_t bigintLength = bigint->GetLength();
358 
359     bool needExpend = true;
360     for (uint32_t i = 0; i < bigintLength; i++) {
361         if (std::numeric_limits<uint32_t>::max() != bigint->GetDigit(i)) {
362             needExpend = false;
363             break;
364         }
365     }
366     uint32_t newLength = bigintLength;
367     if (needExpend) {
368         newLength += 1;
369     }
370     JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, newLength);
371 
372     uint32_t carry = 1;
373     for (uint32_t i = 0; i < bigintLength; i++) {
374         uint32_t bigintCarry = 0;
375         newBigint->SetDigit(i, BigIntHelper::AddHelper(bigint->GetDigit(i), carry, bigintCarry));
376         carry = bigintCarry;
377     }
378     if (needExpend) {
379         newBigint->SetDigit(bigintLength, carry);
380     }
381     newBigint->SetSign(true);
382     return BigIntHelper::RightTruncate(thread, newBigint);
383 }
384 
OneIsNegativeOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)385 JSHandle<BigInt> OneIsNegativeOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
386 {
387     uint32_t xLength = x->GetLength();
388     uint32_t maxLen = xLength;
389     if (maxLen < y->GetLength()) {
390         maxLen = y->GetLength();
391     }
392     JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, maxLen);
393     uint32_t yLength = yVal->GetLength();
394     uint32_t minLen = xLength;
395     if (minLen > yLength) {
396         minLen = yLength;
397     }
398     JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, yLength);
399     uint32_t i = 0;
400     while (i < minLen) {
401         uint32_t res = ~(x->GetDigit(i)) & yVal->GetDigit(i);
402         newBigint->SetDigit(i, res);
403         ++i;
404     }
405     while (i < yLength) {
406         newBigint->SetDigit(i, yVal->GetDigit(i));
407         ++i;
408     }
409     JSHandle<BigInt> temp = BigIntHelper::RightTruncate(thread, newBigint);
410     JSHandle<BigInt> res = BigInt::BitwiseAddOne(thread, temp);
411     res->SetSign(true);
412     return res;
413 }
414 
415 // 6.1.6.2.22 BigInt::bitwiseOR ( x, y )
BitwiseOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)416 JSHandle<BigInt> BigInt::BitwiseOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
417 {
418     if (x->GetSign() && y->GetSign()) {
419         // (-x) | (-y) == -(((x-1) & (y-1)) + 1)
420         uint32_t maxLen = x->GetLength();
421         uint32_t yLen = y->GetLength();
422         maxLen < yLen ? maxLen = yLen : 0;
423         JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, maxLen);
424         JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, yLen);
425         JSHandle<BigInt> temp = BitwiseOp(thread, Operate::AND, xVal, yVal);
426         JSHandle<BigInt> res = BitwiseAddOne(thread, temp);
427         res->SetSign(true);
428         return res;
429     }
430     if (x->GetSign() != y->GetSign()) {
431         // x | (-y) == -(((y-1) & ~x) + 1)
432         if (!x->GetSign()) {
433             return OneIsNegativeOR(thread, x, y);
434         } else {
435             return OneIsNegativeOR(thread, y, x);
436         }
437     }
438     return BitwiseOp(thread, Operate::OR, x, y);
439 }
440 
441 // 6.1.6.2.23 BigInt::toString ( x )
ToString(JSThread * thread,JSHandle<BigInt> bigint,uint32_t conversionToRadix)442 JSHandle<EcmaString> BigInt::ToString(JSThread *thread, JSHandle<BigInt> bigint, uint32_t conversionToRadix)
443 {
444     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
445     CString result = bigint->ToStdString(conversionToRadix);
446     return factory->NewFromASCII(result.c_str());
447 }
448 
ToStdString(uint32_t conversionToRadix) const449 CString BigInt::ToStdString(uint32_t conversionToRadix) const
450 {
451     CString result =
452         BigIntHelper::Conversion(BigIntHelper::GetBinary(this), conversionToRadix, BINARY);
453     if (GetSign()) {
454         result = "-" + result;
455     }
456     return result;
457 }
458 
NumberToBigInt(JSThread * thread,JSHandle<JSTaggedValue> number)459 JSTaggedValue BigInt::NumberToBigInt(JSThread *thread, JSHandle<JSTaggedValue> number)
460 {
461     if (!number->IsInteger()) {
462         THROW_RANGE_ERROR_AND_RETURN(thread, "The number cannot be converted to a BigInt because it is not an integer",
463                                      JSTaggedValue::Exception());
464     }
465     double num = number->GetNumber();
466     if (num == 0.0) {
467         return Int32ToBigInt(thread, 0).GetTaggedValue();
468     }
469 
470     // Bit operations must be of integer type
471     uint64_t bits = 0;
472     if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) {
473         LOG_FULL(FATAL) << "memcpy_s failed";
474         UNREACHABLE();
475     }
476     // Take out bits 62-52 (11 bits in total) and subtract 1023
477     uint64_t integerDigits = ((bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FF) - base::DOUBLE_EXPONENT_BIAS;
478     uint32_t mayNeedLen = integerDigits / DATEBITS + 1;
479 
480     JSHandle<BigInt> bigint = CreateBigint(thread, mayNeedLen);
481     bigint->SetSign(num < 0);
482     uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT;
483     int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE;
484 
485     int leftover = 0;
486     bool isFirstInto = true;
487     for (int index = static_cast<int>(mayNeedLen - 1); index >= 0; --index) {
488         uint32_t doubleNum = 0;
489         if (isFirstInto) {
490             isFirstInto = false;
491             leftover = mantissaSize - static_cast<int>(integerDigits % DATEBITS);
492             doubleNum = static_cast<uint32_t>(mantissa >> leftover);
493             mantissa = mantissa << (64 - leftover); // 64 : double bits size
494             bigint->SetDigit(index, doubleNum);
495         } else {
496             leftover -= DATEBITS;
497             doubleNum = static_cast<uint32_t>(mantissa >> DATEBITS);
498             mantissa = mantissa << DATEBITS;
499             bigint->SetDigit(index, doubleNum);
500         }
501     }
502     return BigIntHelper::RightTruncate(thread, bigint).GetTaggedValue();
503 }
504 
Int32ToBigInt(JSThread * thread,const int & number)505 JSHandle<BigInt> BigInt::Int32ToBigInt(JSThread *thread, const int &number)
506 {
507     JSHandle<BigInt> bigint = CreateBigint(thread, 1);
508     uint32_t value = 0;
509     bool sign = number < 0;
510     if (sign) {
511         value = static_cast<uint32_t>(-(number + 1)) + 1;
512     } else {
513         value = number;
514     }
515     bigint->SetDigit(0, value);
516     bigint->SetSign(sign);
517     return bigint;
518 }
519 
Uint32ToBigInt(JSThread * thread,const uint32_t & number)520 JSHandle<BigInt> BigInt::Uint32ToBigInt(JSThread *thread, const uint32_t &number)
521 {
522     JSHandle<BigInt> bigint = CreateBigint(thread, 1);
523     bigint->SetDigit(0, number);
524     return bigint;
525 }
526 
Int64ToBigInt(JSThread * thread,const int64_t & number)527 JSHandle<BigInt> BigInt::Int64ToBigInt(JSThread *thread, const int64_t &number)
528 {
529     uint64_t value = 0;
530     bool sign = number < 0;
531     if (sign) {
532         value = static_cast<uint64_t>(-(number + 1)) + 1;
533     } else {
534         value = number;
535     }
536     JSHandle<BigInt> bigint = Uint64ToBigInt(thread, value);
537     bigint->SetSign(sign);
538     return BigIntHelper::RightTruncate(thread, bigint);
539 }
540 
Uint64ToBigInt(JSThread * thread,const uint64_t & number)541 JSHandle<BigInt> BigInt::Uint64ToBigInt(JSThread *thread, const uint64_t &number)
542 {
543     JSHandle<BigInt> bigint = CreateBigint(thread, 2); // 2 : one int64_t bits need two uint32_t bits
544     uint32_t lowBits = static_cast<uint32_t>(number & 0xffffffff);
545     uint32_t highBits = static_cast<uint32_t>((number >> DATEBITS) & 0xffffffff);
546     bigint->SetDigit(0, lowBits);
547     bigint->SetDigit(1, highBits);
548     return BigIntHelper::RightTruncate(thread, bigint);
549 }
550 
ToUint64()551 uint64_t BigInt::ToUint64()
552 {
553     uint32_t len = GetLength();
554     ASSERT(len <= 2); // The maximum length of the BigInt data is less or equal 2
555     uint32_t lowBits = GetDigit(0);
556     uint32_t highBits = 0;
557     if (len > 1) {
558         highBits = GetDigit(1);
559     }
560     uint64_t value = static_cast<uint64_t>(lowBits);
561     value |= static_cast<uint64_t>(highBits) << DATEBITS;
562     if (GetSign()) {
563         value = ~(value - 1);
564     }
565     return value;
566 }
567 
ToInt64()568 int64_t BigInt::ToInt64()
569 {
570     return static_cast<int64_t>(ToUint64());
571 }
572 
BigIntToInt64(JSThread * thread,JSHandle<JSTaggedValue> bigint,int64_t * cValue,bool * lossless)573 void BigInt::BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless)
574 {
575     ASSERT(cValue != nullptr);
576     ASSERT(lossless != nullptr);
577     JSHandle<BigInt> bigInt64(thread, JSTaggedValue::ToBigInt64(thread, bigint));
578     RETURN_IF_ABRUPT_COMPLETION(thread);
579     if (Equal(bigInt64.GetTaggedValue(), bigint.GetTaggedValue())) {
580         *lossless = true;
581     }
582     *cValue = bigInt64->ToInt64();
583 }
584 
BigIntToUint64(JSThread * thread,JSHandle<JSTaggedValue> bigint,uint64_t * cValue,bool * lossless)585 void BigInt::BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless)
586 {
587     ASSERT(cValue != nullptr);
588     ASSERT(lossless != nullptr);
589     JSHandle<BigInt> bigUint64(thread, JSTaggedValue::ToBigUint64(thread, bigint));
590     RETURN_IF_ABRUPT_COMPLETION(thread);
591     if (Equal(bigUint64.GetTaggedValue(), bigint.GetTaggedValue())) {
592         *lossless = true;
593     }
594     *cValue = bigUint64->ToUint64();
595 }
596 
CreateBigWords(JSThread * thread,bool sign,uint32_t size,const uint64_t * words)597 JSHandle<BigInt> BigInt::CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t *words)
598 {
599     ASSERT(words != nullptr);
600     if (size == 0) {
601         return Uint64ToBigInt(thread, 0);
602     }
603     const uint32_t MULTIPLE = 2;
604     uint32_t needLen = size * MULTIPLE;
605     if (needLen > MAXSIZE) {
606         JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
607         THROW_RANGE_ERROR_AND_RETURN(thread, "Maximum BigInt size exceeded", bigint);
608     }
609     JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
610     for (uint32_t index = 0; index < size; ++index) {
611         uint32_t lowBits = static_cast<uint32_t>(words[index] & 0xffffffff);
612         uint32_t highBits = static_cast<uint32_t>((words[index] >> DATEBITS) & 0xffffffff);
613         bigint->SetDigit(MULTIPLE * index, lowBits);
614         bigint->SetDigit(MULTIPLE * index + 1, highBits);
615     }
616     bigint->SetSign(sign);
617     return BigIntHelper::RightTruncate(thread, bigint);
618 }
619 
Add(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)620 JSHandle<BigInt> BigInt::Add(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
621 {
622     bool xSignFlag = x->GetSign();
623     bool ySignFlag = y->GetSign();
624     // x + y == x + y
625     // -x + -y == -(x + y)
626     if (xSignFlag == ySignFlag) {
627         return BigintAdd(thread, x, y, xSignFlag);
628     }
629     // x + -y == x - y == -(y - x)
630     // -x + y == y - x == -(x - y)
631     uint32_t xLength = x->GetLength();
632     uint32_t yLength = y->GetLength();
633     int i = static_cast<int>(xLength) - 1;
634     int subSize = static_cast<int>(xLength - yLength);
635     if (subSize > 0) {
636         return BigintSub(thread, x, y, xSignFlag);
637     } else if (subSize == 0) {
638         while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
639             i--;
640         }
641         if ((x->GetDigit(i) > y->GetDigit(i))) {
642             return BigintSub(thread, x, y, xSignFlag);
643         } else {
644             return BigintSub(thread, y, x, ySignFlag);
645         }
646     } else {
647         return BigintSub(thread, y, x, ySignFlag);
648     }
649 }
Subtract(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)650 JSHandle<BigInt> BigInt::Subtract(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
651 {
652     bool xSignFlag = x->GetSign();
653     bool ySignFlag = y->GetSign();
654     if (xSignFlag != ySignFlag) {
655         // x - (-y) == x + y
656         // (-x) - y == -(x + y)
657         return BigintAdd(thread, x, y, xSignFlag);
658     }
659     // x - y == -(y - x)
660     // (-x) - (-y) == y - x == -(x - y)
661     uint32_t xLength = x->GetLength();
662     uint32_t yLength = y->GetLength();
663     uint32_t i = xLength - 1;
664     int subSize = static_cast<int>(xLength - yLength);
665     if (subSize > 0) {
666         return BigintSub(thread, x, y, xSignFlag);
667     } else if (subSize == 0) {
668         while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
669             i--;
670         }
671         if ((x->GetDigit(i) > y->GetDigit(i))) {
672             return BigintSub(thread, x, y, xSignFlag);
673         } else {
674             return BigintSub(thread, y, x, !ySignFlag);
675         }
676     } else {
677         return BigintSub(thread, y, x, !ySignFlag);
678     }
679 }
680 
BigintAdd(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y,bool resultSign)681 JSHandle<BigInt> BigInt::BigintAdd(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign)
682 {
683     if (x->GetLength() < y->GetLength()) {
684         return BigintAdd(thread, y, x, resultSign);
685     }
686     JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength() + 1);
687     uint32_t bigintCarry = 0;
688     uint32_t i = 0;
689     while (i < y->GetLength()) {
690         uint32_t newBigintCarry = 0;
691         uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry);
692         addPlus = BigIntHelper::AddHelper(addPlus, bigintCarry, newBigintCarry);
693         bigint->SetDigit(i, addPlus);
694         bigintCarry = newBigintCarry;
695         i++;
696     }
697     while (i < x->GetLength()) {
698         uint32_t newBigintCarry = 0;
699         uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
700         bigint->SetDigit(i, addPlus);
701         bigintCarry = newBigintCarry;
702         i++;
703     }
704     bigint->SetDigit(i, bigintCarry);
705     bigint->SetSign(resultSign);
706     return BigIntHelper::RightTruncate(thread, bigint);
707 }
708 
AddHelper(uint32_t x,uint32_t y,uint32_t & bigintCarry)709 inline uint32_t BigIntHelper::AddHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry)
710 {
711     uint32_t addPlus = x + y;
712     if (addPlus < x) {
713         bigintCarry += 1;
714     }
715     return addPlus;
716 }
717 
BigintSub(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y,bool resultSign)718 JSHandle<BigInt> BigInt::BigintSub(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign)
719 {
720     JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength());
721     uint32_t bigintCarry = 0;
722     uint32_t i = 0;
723     while (i < y->GetLength()) {
724         uint32_t newBigintCarry = 0;
725         uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry);
726         minuSub = BigIntHelper::SubHelper(minuSub, bigintCarry, newBigintCarry);
727         bigint->SetDigit(i, minuSub);
728         bigintCarry = newBigintCarry;
729         i++;
730     }
731     while (i < x->GetLength()) {
732         uint32_t newBigintCarry = 0;
733         uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
734         bigint->SetDigit(i, minuSub);
735         bigintCarry = newBigintCarry;
736         i++;
737     }
738     bigint->SetSign(resultSign);
739     return BigIntHelper::RightTruncate(thread, bigint);
740 }
741 
BigintAddOne(JSThread * thread,JSHandle<BigInt> x)742 JSHandle<BigInt> BigInt::BigintAddOne(JSThread *thread, JSHandle<BigInt> x)
743 {
744     JSHandle<BigInt> temp = Int32ToBigInt(thread, 1);
745     return Add(thread, x, temp);
746 }
747 
BigintSubOne(JSThread * thread,JSHandle<BigInt> x)748 JSHandle<BigInt> BigInt::BigintSubOne(JSThread *thread, JSHandle<BigInt> x)
749 {
750     JSHandle<BigInt> temp = Int32ToBigInt(thread, 1);
751     return Subtract(thread, x, temp);
752 }
753 
SubHelper(uint32_t x,uint32_t y,uint32_t & bigintCarry)754 inline uint32_t BigIntHelper::SubHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry)
755 {
756     uint32_t minuSub = x - y;
757     if (minuSub > x) {
758         bigintCarry += 1;
759     }
760     return minuSub;
761 }
762 
Compare(const JSTaggedValue & x,const JSTaggedValue & y)763 ComparisonResult BigInt::Compare(const JSTaggedValue &x, const JSTaggedValue &y)
764 {
765     BigInt* xVal = BigInt::Cast(x.GetTaggedObject());
766     BigInt* yVal = BigInt::Cast(y.GetTaggedObject());
767     return Compare(xVal, yVal);
768 }
769 
Compare(const BigInt * x,const BigInt * y)770 ComparisonResult BigInt::Compare(const BigInt *x, const BigInt *y)
771 {
772     bool xSign = x->GetSign();
773     bool ySign = y->GetSign();
774     if (xSign != ySign) {
775         return xSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
776     }
777     ComparisonResult compar = AbsolutelyCompare(x, y);
778     if (xSign && compar != ComparisonResult::EQUAL) {
779         return compar == ComparisonResult::LESS ? ComparisonResult::GREAT : ComparisonResult::LESS;
780     }
781     return compar;
782 }
783 
LessThan(const JSTaggedValue & x,const JSTaggedValue & y)784 bool BigInt::LessThan(const JSTaggedValue &x, const JSTaggedValue &y)
785 {
786     return Compare(x, y) == ComparisonResult::LESS;
787 }
788 
LessThan(const BigInt * x,const BigInt * y)789 bool BigInt::LessThan(const BigInt *x, const BigInt *y)
790 {
791     ASSERT(x != nullptr);
792     ASSERT(y != nullptr);
793     return Compare(x, y) == ComparisonResult::LESS;
794 }
795 
SignedRightShift(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)796 JSHandle<BigInt> BigInt::SignedRightShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
797 {
798     bool xIsNull = x->GetDigit(0);
799     bool yIsNull = y->GetDigit(0);
800     if (!xIsNull || !yIsNull) {
801         return x;
802     }
803     if (y->GetSign()) {
804         return LeftShiftHelper(thread, x, y);
805     } else {
806         return RightShiftHelper(thread, x, y);
807     }
808 }
809 
ReturnIfRightShiftOverMax(JSThread * thread,bool sign)810 JSHandle<BigInt> BigInt::ReturnIfRightShiftOverMax(JSThread *thread, bool sign)
811 {
812     if (sign) {
813         return Int32ToBigInt(thread, -1);
814     }
815     return Int32ToBigInt(thread, 0);
816 }
817 
RightShift(JSHandle<BigInt> bigint,JSHandle<BigInt> x,uint32_t digitMove,uint32_t bitsMove)818 void BigInt::RightShift(JSHandle<BigInt> bigint, JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove)
819 {
820     uint32_t size = x->GetLength();
821     if (bitsMove == 0) {
822         for (uint32_t i = digitMove; i < size; i++) {
823             bigint->SetDigit(i - digitMove, x->GetDigit(i));
824         }
825     } else {
826         uint32_t carry = x->GetDigit(digitMove) >> bitsMove;
827         uint32_t last = size - digitMove - 1;
828         for (uint32_t i = 0; i < last; i++) {
829             uint32_t value = x->GetDigit(i + digitMove + 1);
830             bigint->SetDigit(i, (value << (DATEBITS - bitsMove)) | carry);
831             carry = value >> bitsMove;
832         }
833         bigint->SetDigit(last, carry);
834     }
835 }
836 
JudgeRoundDown(JSHandle<BigInt> x,uint32_t digitMove,uint32_t bitsMove,uint32_t & needLen,bool & roundDown)837 void BigInt::JudgeRoundDown(JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove, uint32_t &needLen,
838                             bool &roundDown)
839 {
840     uint32_t stamp = (static_cast<uint32_t>(1U) << bitsMove) - 1;
841     if (x->GetDigit(digitMove) & stamp) {
842         roundDown = true;
843     } else {
844         for (uint32_t i = 0; i < digitMove; i++) {
845             if (x->GetDigit(i) != 0) {
846                 roundDown = true;
847                 break;
848             }
849         }
850     }
851 
852     if (roundDown && bitsMove == 0) {
853         uint32_t highBits = x->GetDigit(x->GetLength() - 1);
854         // If all the most significant bits are 1, we think that carry will cause overflow,
855         // and needLen needs to be increased by 1
856         if ((~highBits) == 0) {
857             needLen++;
858         }
859     }
860 }
861 
RightShiftHelper(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)862 JSHandle<BigInt> BigInt::RightShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
863 {
864     bool sign = x->GetSign();
865     if (y->GetLength() > 1 || y->GetDigit(0) > MAXBITS) {
866         return ReturnIfRightShiftOverMax(thread, sign);
867     }
868     uint32_t moveNum = y->GetDigit(0);
869     uint32_t digitMove = moveNum / DATEBITS;
870     uint32_t bitsMove = moveNum % DATEBITS;
871     if (x->GetLength() <= digitMove) {
872         return ReturnIfRightShiftOverMax(thread, sign);
873     }
874     uint32_t needLen = x->GetLength() - digitMove;
875     bool roundDown = false;
876     if (sign) {
877         // If it is a negative number, you need to consider whether it will carry after moving.
878         // NeedLen may need to increase by 1
879         JudgeRoundDown(x, digitMove, bitsMove, needLen, roundDown);
880     }
881     JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
882 
883     RightShift(bigint, x, digitMove, bitsMove);
884     bigint = BigIntHelper::RightTruncate(thread, bigint);
885     if (sign) {
886         bigint->SetSign(true);
887         if (roundDown) {
888             return BitwiseAddOne(thread, bigint);
889         }
890     }
891     return bigint;
892 }
893 
LeftShift(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)894 JSHandle<BigInt> BigInt::LeftShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
895 {
896     if (y->GetSign()) {
897         return RightShiftHelper(thread, x, y);
898     } else {
899         return LeftShiftHelper(thread, x, y);
900     }
901 }
902 
LeftShiftHelper(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)903 JSHandle<BigInt> BigInt::LeftShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
904 {
905     ASSERT(y->GetLength() == 1);
906     ASSERT(y->GetDigit(0) <= MAXBITS);
907     uint32_t moveNum = y->GetDigit(0);
908     uint32_t digitMove = moveNum / DATEBITS;
909     uint32_t bitsMove = moveNum % DATEBITS;
910     // If bitsMove is not zero, needLen needs to be increased by 1
911     uint32_t needLen = digitMove + x->GetLength() + static_cast<uint32_t>(!!bitsMove);
912     ASSERT(needLen < MAXSIZE);
913     JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
914     if (bitsMove == 0) {
915         uint32_t index = digitMove;
916         while (index < needLen) {
917             bigint->SetDigit(index, x->GetDigit(index - digitMove));
918             ++index;
919         }
920     } else {
921         uint32_t carry = 0;
922         uint32_t index = 0;
923         while (index < x->GetLength()) {
924             uint32_t value = x->GetDigit(index);
925             bigint->SetDigit(index + digitMove, (value << bitsMove) | carry);
926             carry = value >> (DATEBITS - bitsMove);
927             ++index;
928         }
929         if (carry != 0) {
930             ASSERT(index + digitMove < needLen);
931             bigint->SetDigit(index + digitMove, carry);
932         }
933     }
934     bigint->SetSign(x->GetSign());
935     return BigIntHelper::RightTruncate(thread, bigint);
936 }
937 
UnsignedRightShift(JSThread * thread)938 JSTaggedValue BigInt::UnsignedRightShift(JSThread *thread)
939 {
940     THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt have no unsigned right shift, use >> instead",
941                                 JSTaggedValue::Exception());
942 }
943 
Copy(JSThread * thread,JSHandle<BigInt> x,uint32_t len)944 JSHandle<BigInt> BigInt::Copy(JSThread *thread, JSHandle<BigInt> x, uint32_t len)
945 {
946     ASSERT(x->GetLength() >= len);
947     JSHandle<BigInt> newBig = CreateBigint(thread, len);
948     std::copy(x->GetData(), x->GetData() + len, newBig->GetData());
949     newBig->SetSign(x->GetSign());
950     return newBig;
951 }
952 
UnaryMinus(JSThread * thread,JSHandle<BigInt> x)953 JSHandle<BigInt> BigInt::UnaryMinus(JSThread *thread, JSHandle<BigInt> x)
954 {
955     if (x->IsZero()) {
956         return x;
957     }
958     JSHandle<BigInt> y = Copy(thread, x, x->GetLength());
959     y->SetSign(!y->GetSign());
960     return y;
961 }
962 
963 // 6.1.6.2.2   BigInt::bitwiseNOT ( x )
BitwiseNOT(JSThread * thread,JSHandle<BigInt> x)964 JSHandle<BigInt> BigInt::BitwiseNOT(JSThread *thread, JSHandle<BigInt> x)
965 {
966     // ~(-x) == ~(~(x-1)) == x-1
967     // ~x == -x-1 == -(x+1)
968     JSHandle<BigInt> result = BigintAddOne(thread, x);
969     if (x->GetSign()) {
970         result->SetSign(false);
971     } else {
972         result->SetSign(true);
973     }
974     return result;
975 }
976 
Exponentiate(JSThread * thread,JSHandle<BigInt> base,JSHandle<BigInt> exponent)977 JSHandle<BigInt> BigInt::Exponentiate(JSThread *thread, JSHandle<BigInt> base, JSHandle<BigInt> exponent)
978 {
979     if (exponent->GetSign()) {
980         JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
981         THROW_RANGE_ERROR_AND_RETURN(thread, "Exponent must be positive", bigint);
982     }
983     ASSERT(exponent->GetLength() == 1);
984     if (exponent->IsZero()) {
985         return Int32ToBigInt(thread, 1);
986     }
987     uint32_t expValue = exponent->GetDigit(0);
988     if (base->IsZero() || expValue == 1) {
989         return base;
990     }
991     if (base->GetLength() == 1 && base->GetDigit(0) == 1) {
992         if (base->GetSign() && !(expValue & 1)) {
993             return BigInt::UnaryMinus(thread, base);
994         }
995         return base;
996     }
997     if (base->GetLength() == 1 && base->GetDigit(0) == 2) { // 2 : We use fast path processing 2 ^ n
998         uint32_t needLength = expValue / DATEBITS + 1;
999         JSHandle<BigInt> bigint = CreateBigint(thread, needLength);
1000         uint32_t value = 1U << (expValue % DATEBITS);
1001         bigint->SetDigit(needLength - 1, value);
1002         if (base->GetSign()) {
1003             bigint->SetSign(static_cast<bool>(expValue & 1));
1004         }
1005         return bigint;
1006     }
1007     JSMutableHandle<BigInt> result(thread, JSTaggedValue::Null());
1008     JSMutableHandle<BigInt> temp(thread, base);
1009     if (expValue & 1) {
1010         result.Update(base);
1011     }
1012     expValue >>= 1;
1013     for (; expValue; expValue >>= 1) {
1014         temp.Update(BigInt::Multiply(thread, temp, temp));
1015         if (expValue & 1) {
1016             if (result.GetTaggedValue().IsNull()) {
1017                 result.Update(temp);
1018             } else {
1019                 result.Update(BigInt::Multiply(thread, result, temp));
1020             }
1021         }
1022     }
1023     ASSERT(result.GetTaggedValue().IsBigInt());
1024     return result;
1025 }
1026 
Mul(uint32_t x,uint32_t y)1027 std::tuple<uint32_t, uint32_t> BigInt::Mul(uint32_t x, uint32_t y)
1028 {
1029     uint32_t lowBitX = x & HALFDATEMASK;
1030     uint32_t highBitX = x >> HALFDATEBITS;
1031     uint32_t lowBitY = y & HALFDATEMASK;
1032     uint32_t highBitY = y >> HALFDATEBITS;
1033     // {highBitX lowBitX} * {highBitY lowBitY}
1034     uint32_t lowRes = lowBitX * lowBitY;
1035     uint32_t highRes = highBitX * highBitY;
1036     uint32_t midRes1 = lowBitX * highBitY;
1037     uint32_t midRes2 = highBitX * lowBitY;
1038 
1039     uint32_t carry = 0;
1040     uint32_t low = BigIntHelper::AddHelper(
1041         BigIntHelper::AddHelper(lowRes, midRes1 << HALFDATEBITS, carry), midRes2 << HALFDATEBITS, carry);
1042     uint32_t high = (midRes1 >> HALFDATEBITS) + (midRes2 >> HALFDATEBITS) + highRes + carry;
1043 
1044     return std::make_tuple(high, low);
1045 }
1046 
Multiply(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)1047 JSHandle<BigInt> BigInt::Multiply(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
1048 {
1049     if (x->IsZero()) {
1050         return x;
1051     }
1052     if (y->IsZero()) {
1053         return y;
1054     }
1055     uint32_t needLength = x->GetLength() + y->GetLength();
1056     JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, needLength);
1057 
1058     // the algorithm here is similar to the way we use paper money to calculate multiplication.
1059     // Generally, we first calculate the partial product, and then add up to get the result.
1060     // The only difference here is that multiplication and addition are calculated synchronously
1061     for (uint32_t i = 0; i < x->GetLength(); i++) {
1062         uint32_t xVal = x->GetDigit(i);
1063         // If the current multiplier is 0, we will skip this round of calculation to improve performance.
1064         // If we do not skip, the correctness of the calculation will not be affected
1065         if (xVal == 0) {
1066             continue;
1067         }
1068         uint32_t carry = 0;
1069         uint32_t high = 0;
1070         uint32_t index = i;
1071         for (uint32_t j = 0; j < y->GetLength(); j++) {
1072             uint32_t currentCarry = 0;
1073             uint32_t value = bigint->GetDigit(index);
1074             value = BigIntHelper::AddHelper(value, high, currentCarry);
1075             value = BigIntHelper::AddHelper(value, carry, currentCarry);
1076 
1077             uint32_t low;
1078             std::tie(high, low) = Mul(xVal, y->GetDigit(j));
1079             value = BigIntHelper::AddHelper(value, low, currentCarry);
1080             bigint->SetDigit(index, value);
1081             carry = currentCarry;
1082             index++;
1083         }
1084         while (carry != 0 || high != 0) {
1085             ASSERT(index < bigint->GetLength());
1086             uint32_t value = bigint->GetDigit(index);
1087             uint32_t currentCarry = 0;
1088             value = BigIntHelper::AddHelper(value, high, currentCarry);
1089             high = 0;
1090             value = BigIntHelper::AddHelper(value, carry, currentCarry);
1091             bigint->SetDigit(index, value);
1092             carry = currentCarry;
1093             index++;
1094         }
1095     }
1096 
1097     bigint->SetSign(x->GetSign() != y->GetSign());
1098     return BigIntHelper::RightTruncate(thread, bigint);
1099 }
1100 
DeZero(CString & a)1101 void BigIntHelper::DeZero(CString &a)
1102 {
1103     size_t count = 0;
1104     while (count < a.size() && a[count] == '0') {
1105         count++;
1106     }
1107     if (count == a.size()) {
1108         a = "0";
1109     } else {
1110         a = a.substr(count);
1111     }
1112 }
1113 
AbsolutelyCompare(const BigInt * x,const BigInt * y)1114 ComparisonResult BigInt::AbsolutelyCompare(const BigInt *x, const BigInt *y)
1115 {
1116     uint32_t xLen = x->GetLength();
1117     uint32_t yLen = y->GetLength();
1118     if (xLen > yLen) {
1119         return ComparisonResult::GREAT;
1120     } else if (xLen < yLen) {
1121         return ComparisonResult::LESS;
1122     } else {
1123         int index = static_cast<int>(xLen) - 1;
1124         for (; index >= 0; --index) {
1125             if (x->GetDigit(index) != y->GetDigit(index)) {
1126                 break;
1127             }
1128         }
1129         if (index < 0) {
1130             return ComparisonResult::EQUAL;
1131         }
1132         return x->GetDigit(index) > y->GetDigit(index) ? ComparisonResult::GREAT : ComparisonResult::LESS;
1133     }
1134 }
1135 
DivideAndRemainder(uint32_t highBit,uint32_t lowBit,uint32_t divisor,uint32_t & remainder)1136 uint32_t BigInt::DivideAndRemainder(uint32_t highBit, uint32_t lowBit, uint32_t divisor, uint32_t& remainder)
1137 {
1138     uint32_t leadingZeros = base::CountLeadingZeros(divisor);
1139     // Before calculating, we need to align the operands to the left
1140     divisor <<= leadingZeros;
1141     uint32_t lowDividend = lowBit << leadingZeros;
1142     uint32_t highDividend = highBit;
1143     if (leadingZeros != 0) {
1144         // highBit is the remainder of the last calculation, which must be less than or equal to the divisor,
1145         // so high << leadingZeros will not lose the significant bit
1146         highDividend = (highBit << leadingZeros) | (lowBit >> (DATEBITS - leadingZeros));
1147     }
1148     uint32_t highDivisor = divisor >> HALFDATEBITS;
1149     uint32_t lowDivisor = divisor & HALFDATEMASK;
1150     uint32_t lowDividend1 = lowDividend >> HALFDATEBITS;
1151     uint32_t lowDividend2 = lowDividend & HALFDATEMASK;
1152     uint32_t highQuotient = highDividend / highDivisor;
1153     uint32_t tempRemainder = highDividend - highQuotient * highDivisor;
1154 
1155     // Similar to the ordinary division calculation, here we use HALFUINT32VALUE as the carry unit
1156     // Calculate high order results first
1157     while (highQuotient >= HALFUINT32VALUE ||
1158            highQuotient * lowDivisor > tempRemainder * HALFUINT32VALUE + lowDividend1) {
1159         highQuotient--;
1160         tempRemainder += highDivisor;
1161         if (tempRemainder >= HALFUINT32VALUE)
1162             break;
1163     }
1164     uint32_t tempLowDividend = highDividend * HALFUINT32VALUE + lowDividend1 - highQuotient * divisor;
1165     uint32_t lowQuotient = tempLowDividend / highDivisor;
1166     tempRemainder = tempLowDividend - lowQuotient * highDivisor;
1167 
1168     // Then calculate the low order result
1169     while (lowQuotient >= HALFUINT32VALUE ||
1170            lowQuotient * lowDivisor > tempRemainder * HALFUINT32VALUE + lowDividend2) {
1171         lowQuotient--;
1172         tempRemainder += highDivisor;
1173         if (tempRemainder >= HALFUINT32VALUE)
1174             break;
1175     }
1176 
1177     // In order to facilitate the calculation, we start to make left alignment
1178     // At this time, we need to move right to get the correct remainder
1179     remainder = (tempLowDividend * HALFUINT32VALUE + lowDividend2 - lowQuotient * divisor) >> leadingZeros;
1180     return highQuotient * HALFUINT32VALUE + lowQuotient;
1181 }
1182 
FormatLeftShift(JSThread * thread,uint32_t shift,JSHandle<BigInt> bigint,bool neeedAddOne)1183 JSHandle<BigInt> BigInt::FormatLeftShift(JSThread *thread, uint32_t shift, JSHandle<BigInt> bigint, bool neeedAddOne)
1184 {
1185     if (!neeedAddOne && shift == 0) {
1186         return bigint;
1187     }
1188     uint32_t len = bigint->GetLength();
1189     uint32_t needLen = len;
1190     if (neeedAddOne) {
1191         needLen += 1;
1192     }
1193     JSHandle<BigInt> result = CreateBigint(thread, needLen);
1194     if (shift == 0) {
1195         std::copy(bigint->GetData(), bigint->GetData() + len, result->GetData());
1196     } else {
1197         uint32_t carry = 0;
1198         uint32_t index = 0;
1199         while (index < len) {
1200             uint32_t value = bigint->GetDigit(index);
1201             result->SetDigit(index, (value << shift) | carry);
1202             carry = value >> (DATEBITS - shift);
1203             index++;
1204         }
1205         if (carry != 0) {
1206             ASSERT(neeedAddOne);
1207             result->SetDigit(index, carry);
1208         }
1209     }
1210     return result;
1211 }
1212 
UnformattedRightShift(JSHandle<BigInt> bigint,uint32_t shift)1213 void BigInt::UnformattedRightShift(JSHandle<BigInt> bigint, uint32_t shift)
1214 {
1215     RightShift(bigint, bigint, 0, shift);
1216 }
1217 
SpecialMultiplyAndSub(JSHandle<BigInt> u,JSHandle<BigInt> v,uint32_t q,JSHandle<BigInt> qv,uint32_t pos)1218 bool BigInt::SpecialMultiplyAndSub(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t q, JSHandle<BigInt> qv,
1219                                    uint32_t pos)
1220 {
1221     uint32_t lastCarry = 0;
1222     uint32_t lastHigh = 0;
1223     uint32_t len = v->GetLength();
1224     // Calculate multiplication first
1225     for (uint32_t i = 0; i < len; ++i) {
1226         uint32_t value = v->GetDigit(i);
1227         uint32_t carry = 0;
1228         uint32_t high = 0;
1229         std::tie(high, value) = Mul(value, q);
1230         // The current value plus the high and carry of the last calculation
1231         value = BigIntHelper::AddHelper(value, lastHigh, carry);
1232         value = BigIntHelper::AddHelper(value, lastCarry, carry);
1233         qv->SetDigit(i, value);
1234         // Record the new high bit and carry for the next round
1235         lastCarry = carry;
1236         lastHigh = high;
1237     }
1238     qv->SetDigit(len, lastHigh + lastCarry);
1239 
1240     // Next, subtract
1241     uint32_t lastBorrow = 0;
1242     for (uint32_t i = 0; i < qv->GetLength(); ++i) {
1243         uint32_t borrow = 0;
1244         uint32_t value = BigIntHelper::SubHelper(u->GetDigit(pos + i), qv->GetDigit(i), borrow);
1245         value = BigIntHelper::SubHelper(value, lastBorrow, borrow);
1246         u->SetDigit(pos + i, value);
1247         lastBorrow = borrow;
1248     }
1249 
1250     return lastBorrow > 0;
1251 }
1252 
SpecialAdd(JSHandle<BigInt> u,JSHandle<BigInt> v,uint32_t pos)1253 uint32_t BigInt::SpecialAdd(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t pos)
1254 {
1255     uint32_t lastCarry = 0;
1256     for (uint32_t i = 0; i < v->GetLength(); ++i) {
1257         uint32_t carry = 0;
1258         uint32_t value = BigIntHelper::AddHelper(u->GetDigit(pos + i), v->GetDigit(i), carry);
1259         value = BigIntHelper::AddHelper(value, lastCarry, carry);
1260         u->SetDigit(pos + i, value);
1261         lastCarry = carry;
1262     }
1263     return lastCarry;
1264 }
1265 
ImproveAccuracy(uint32_t vHighest,uint32_t vHighestNext,uint32_t UHighest,uint32_t UHighestNext,uint32_t q)1266 uint32_t BigInt::ImproveAccuracy(uint32_t vHighest, uint32_t vHighestNext, uint32_t UHighest,
1267                                  uint32_t UHighestNext, uint32_t q)
1268 {
1269     uint32_t high = 0;
1270     uint32_t low = 0;
1271     std::tie(high, low) = Mul(q, vHighestNext);
1272     while (high > UHighest || (high == UHighest && low > UHighestNext)) {
1273         q--;
1274         UHighest += vHighest;
1275         // if r is less than the current base, continue the next round of inspection. Here,
1276         // we confirm whether r is greater than the current base by judging whether r overflows
1277         if (UHighest < vHighest) {
1278             break;
1279         }
1280         std::tie(high, low) = Mul(q, vHighestNext);
1281     }
1282     return q;
1283 }
1284 
DivideAndRemainderWithBigintDivisor(JSThread * thread,JSHandle<BigInt> dividend,JSHandle<BigInt> divisor,JSMutableHandle<BigInt> & remainder)1285 JSHandle<BigInt> BigInt::DivideAndRemainderWithBigintDivisor(JSThread *thread, JSHandle<BigInt> dividend,
1286                                                              JSHandle<BigInt> divisor,
1287                                                              JSMutableHandle<BigInt> &remainder)
1288 {
1289     uint32_t divisorLen = divisor->GetLength();
1290     // the length of the quota is the length of the dividend minus the divisor
1291     uint32_t quotientLen = dividend->GetLength() - divisorLen;
1292     JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null());
1293     if (remainder.GetTaggedValue().IsNull()) {
1294         quotient.Update(CreateBigint(thread, quotientLen + 1));
1295     }
1296     // format the divisor and dividend so that the highest order of the divisor is
1297     // greater than or equal to half of uint32_t
1298     uint32_t leadingZeros = base::CountLeadingZeros(divisor->GetDigit(divisorLen - 1));
1299     JSHandle<BigInt> v = FormatLeftShift(thread, leadingZeros, divisor, false);
1300     JSHandle<BigInt> u = FormatLeftShift(thread, leadingZeros, dividend, true);
1301     // qv is used to store the result of quotient * divisor of each round
1302     JSHandle<BigInt> qv = CreateBigint(thread, divisorLen + 1);
1303     uint32_t vHighest = v->GetDigit(divisorLen - 1);
1304     for (int i = static_cast<int>(quotientLen); i >= 0; --i) {
1305         uint32_t currentUHighest = u->GetDigit(i + divisorLen);
1306         uint32_t r = 0;
1307         uint32_t q = DivideAndRemainder(currentUHighest, u->GetDigit(i + divisorLen - 1), vHighest, r);
1308         // VHighest = currentUHighest means that q may be equal to the current base
1309         // In the current program, the current base is the maximum value of uint32 plus 1
1310         if (vHighest == currentUHighest) {
1311             q = std::numeric_limits<uint32_t>::max();
1312         } else {
1313             uint32_t vHighestNext = v->GetDigit(divisorLen - 2); // 2 : Get the second most significant bit
1314             uint32_t currentUHighestNext = u->GetDigit(i + divisorLen - 2); // 2 : ditto
1315 
1316             // The following operations will make q only 1 greater than the value we want in most cases,
1317             // and will not be less than it
1318             q = ImproveAccuracy(vHighest, vHighestNext, r, currentUHighestNext, q);
1319         }
1320         // multiplication and subtraction
1321         if (SpecialMultiplyAndSub(u, v, q, qv, i)) {
1322             q--;
1323             uint32_t carry = SpecialAdd(u, v, i);
1324             u->SetDigit(i + divisorLen, u->GetDigit(i + divisorLen) + carry);
1325         }
1326         if (remainder.GetTaggedValue().IsNull()) {
1327             quotient->SetDigit(i, q);
1328         }
1329     }
1330     if (!remainder.GetTaggedValue().IsNull()) {
1331         // at the beginning of this procedure, we performed the left shift operation.
1332         // Here, we get the correct result by shifting the same number of digits to the right
1333         UnformattedRightShift(u, leadingZeros);
1334         remainder.Update(u);
1335     }
1336     return quotient;
1337 }
1338 
DivideAndRemainderWithUint32Divisor(JSThread * thread,JSHandle<BigInt> dividend,uint32_t divisor,JSMutableHandle<BigInt> & remainder)1339 JSHandle<BigInt> BigInt::DivideAndRemainderWithUint32Divisor(JSThread *thread, JSHandle<BigInt> dividend,
1340                                                              uint32_t divisor, JSMutableHandle<BigInt> &remainder)
1341 {
1342     uint32_t r = 0;
1343     JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null());
1344     if (!remainder.GetTaggedValue().IsNull()) {
1345         for (int i = static_cast<int>(dividend->GetLength()) - 1; i >= 0; --i) {
1346             DivideAndRemainder(r, dividend->GetDigit(i), divisor, r);
1347             remainder.Update(Uint32ToBigInt(thread, r));
1348         }
1349     } else {
1350         quotient.Update(CreateBigint(thread, dividend->GetLength()));
1351         for (int i = static_cast<int>(dividend->GetLength()) - 1; i >= 0; --i) {
1352             uint32_t q = DivideAndRemainder(r, dividend->GetDigit(i), divisor, r);
1353             quotient->SetDigit(i, q);
1354         }
1355     }
1356     return quotient;
1357 }
1358 
1359 // The algorithm here refers to algorithm D in Volume 2 of <The Art of Computer Programming>
Divide(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)1360 JSHandle<BigInt> BigInt::Divide(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
1361 {
1362     if (y->IsZero()) {
1363         JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
1364         THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint);
1365     }
1366     // returns 0 if x is less than y
1367     JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null());
1368     bool sign = x->GetSign() != y->GetSign();
1369     ComparisonResult compare = AbsolutelyCompare(*x, *y);
1370     if (compare == ComparisonResult::LESS) {
1371         return Int32ToBigInt(thread, 0);
1372     }
1373     if (compare == ComparisonResult::EQUAL) {
1374         quotient.Update(Int32ToBigInt(thread, 1));
1375         quotient->SetSign(sign);
1376         return quotient;
1377     }
1378     // if y is 1, return +x or -x
1379     if (y->IsUint32() && y->GetDigit(0) == 1) {
1380         if (sign == x->GetSign()) {
1381             return x;
1382         }
1383         return UnaryMinus(thread, x);
1384     }
1385     JSMutableHandle<BigInt> remainder(thread, JSTaggedValue::Null());
1386     if (y->IsUint32()) {
1387         // When the divisor is uint32_t, we have a faster and simpler algorithm to calculate
1388         quotient.Update(DivideAndRemainderWithUint32Divisor(thread, x, y->GetDigit(0), remainder));
1389     } else {
1390         ASSERT(y->GetLength() >= 1); // 1 : Entering the current branch length must be greater than 1
1391         quotient.Update(DivideAndRemainderWithBigintDivisor(thread, x, y, remainder));
1392     }
1393     ASSERT(quotient.GetTaggedValue().IsBigInt());
1394     quotient->SetSign(sign);
1395     return BigIntHelper::RightTruncate(thread, quotient);
1396 }
1397 
Remainder(JSThread * thread,JSHandle<BigInt> n,JSHandle<BigInt> d)1398 JSHandle<BigInt> BigInt::Remainder(JSThread *thread, JSHandle<BigInt> n, JSHandle<BigInt> d)
1399 {
1400     if (d->IsZero()) {
1401         JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
1402         THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint);
1403     }
1404     ComparisonResult compare = AbsolutelyCompare(*n, *d);
1405     if (n->IsZero() || compare == ComparisonResult::LESS) {
1406         return n;
1407     }
1408     if (compare == ComparisonResult::EQUAL || (d->IsUint32() && d->GetDigit(0) == 1)) {
1409         return Int32ToBigInt(thread, 0);
1410     }
1411     JSMutableHandle<BigInt> remainder(thread, JSTaggedValue::Undefined());
1412     if (d->IsUint32()) {
1413         // When the divisor is uint32_t, we have a faster and simpler algorithm to calculate
1414         DivideAndRemainderWithUint32Divisor(thread, n, d->GetDigit(0), remainder);
1415     } else {
1416         ASSERT(d->GetLength() > 1); // 1 : Entering the current branch length must be greater than 1
1417         DivideAndRemainderWithBigintDivisor(thread, n, d, remainder);
1418     }
1419     ASSERT(remainder.GetTaggedValue().IsBigInt());
1420     remainder->SetSign(n->GetSign());
1421     return BigIntHelper::RightTruncate(thread, remainder);
1422 }
1423 
FloorMod(JSThread * thread,JSHandle<BigInt> leftVal,JSHandle<BigInt> rightVal)1424 JSHandle<BigInt> BigInt::FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal)
1425 {
1426     JSHandle<BigInt> remainder = Remainder(thread, leftVal, rightVal);
1427     if (leftVal->GetSign() && !remainder->IsZero()) {
1428         return Add(thread, remainder, rightVal);
1429     }
1430     return remainder;
1431 }
1432 
AsUintN(JSThread * thread,JSTaggedNumber & bits,JSHandle<BigInt> bigint)1433 JSTaggedValue BigInt::AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint)
1434 {
1435     uint32_t bit = bits.ToUint32();
1436     if (bit == 0) {
1437         return Int32ToBigInt(thread, 0).GetTaggedValue();
1438     }
1439     if (bigint->IsZero()) {
1440         return bigint.GetTaggedValue();
1441     }
1442     JSHandle<BigInt> exponent = Int32ToBigInt(thread, bit);
1443     JSHandle<BigInt> base = Int32ToBigInt(thread, 2); // 2 : base value
1444     JSHandle<BigInt> tValue = Exponentiate(thread, base, exponent);
1445     return FloorMod(thread, bigint, tValue).GetTaggedValue();
1446 }
1447 
AsintN(JSThread * thread,JSTaggedNumber & bits,JSHandle<BigInt> bigint)1448 JSTaggedValue BigInt::AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint)
1449 {
1450     uint32_t bit = bits.ToUint32();
1451     if (bit == 0) {
1452         return Int32ToBigInt(thread, 0).GetTaggedValue();
1453     }
1454     if (bigint->IsZero()) {
1455         return bigint.GetTaggedValue();
1456     }
1457     JSHandle<BigInt> exp = Int32ToBigInt(thread, bit);
1458     JSHandle<BigInt> exponent = Int32ToBigInt(thread, bit - 1);
1459     JSHandle<BigInt> base = Int32ToBigInt(thread, 2); // 2 : base value
1460     JSHandle<BigInt> tValue = Exponentiate(thread, base, exp);
1461     JSHandle<BigInt> modValue =  FloorMod(thread, bigint, tValue);
1462     JSHandle<BigInt> resValue = Exponentiate(thread, base, exponent);
1463     // If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return (mod).
1464     if (Compare(*resValue, *modValue) != ComparisonResult::GREAT) {
1465         return Subtract(thread, modValue, tValue).GetTaggedValue();
1466     }
1467     return modValue.GetTaggedValue();
1468 }
1469 
CalculateNumber(const uint64_t & sign,const uint64_t & mantissa,uint64_t & exponent)1470 static JSTaggedNumber CalculateNumber(const uint64_t &sign, const uint64_t &mantissa, uint64_t &exponent)
1471 {
1472     exponent = (exponent + base::DOUBLE_EXPONENT_BIAS) << base::DOUBLE_SIGNIFICAND_SIZE;
1473     uint64_t doubleBit = sign | exponent | mantissa;
1474     double res = 0;
1475     if (memcpy_s(&res, sizeof(res), &doubleBit, sizeof(doubleBit)) != EOK) {
1476         LOG_FULL(FATAL) << "memcpy_s failed";
1477         UNREACHABLE();
1478     }
1479     return JSTaggedNumber(res);
1480 }
1481 
Rounding(const uint64_t & sign,uint64_t & mantissa,uint64_t & exponent,bool needRound)1482 static JSTaggedNumber Rounding(const uint64_t &sign, uint64_t &mantissa, uint64_t &exponent, bool needRound)
1483 {
1484     if (needRound || (mantissa & 1) == 1) {
1485         ++mantissa;
1486         if ((mantissa >> base::DOUBLE_SIGNIFICAND_SIZE) != 0) {
1487             mantissa = 0;
1488             exponent++;
1489             if (exponent > base::DOUBLE_EXPONENT_BIAS)
1490                 return JSTaggedNumber(sign ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY);
1491         }
1492     }
1493     return CalculateNumber(sign, mantissa, exponent);
1494 }
1495 
BigIntToNumber(JSHandle<BigInt> bigint)1496 JSTaggedNumber BigInt::BigIntToNumber(JSHandle<BigInt> bigint)
1497 {
1498     if (bigint->IsZero()) {
1499         return JSTaggedNumber(0);
1500     }
1501     uint32_t bigintLen = bigint->GetLength();
1502     uint32_t BigintHead = bigint->GetDigit(bigintLen - 1);
1503     uint32_t leadingZeros = base::CountLeadingZeros(BigintHead);
1504     int bigintBitLen = static_cast<int>(bigintLen * BigInt::DATEBITS - leadingZeros);
1505     // if Significant bits greater than 1024 then double is infinity
1506     bool bigintSign = bigint->GetSign();
1507     if (bigintBitLen > (base::DOUBLE_EXPONENT_BIAS + 1)) {
1508         return JSTaggedNumber(bigintSign ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY);
1509     }
1510     uint64_t sign = bigintSign ? 1ULL << 63 : 0; // 63 : Set the sign bit of sign to 1
1511     int needMoveBit = static_cast<int>(leadingZeros + BigInt::DATEBITS + 1);
1512     // Align to the most significant bit, then right shift 12 bits so that the head of the mantissa is in place
1513     uint64_t mantissa = (static_cast<uint64_t>(BigintHead) << needMoveBit) >> 12; // 12 mantissa just has 52 bits
1514     int remainMantissaBits = needMoveBit - 12;
1515     uint64_t exponent = static_cast<uint64_t>(bigintBitLen - 1);
1516     int index = static_cast<int>(bigintLen - 1);
1517     uint32_t digit = 0;
1518     if (index > 0) {
1519         digit = bigint->GetDigit(--index);
1520     } else {
1521         return CalculateNumber(sign, mantissa, exponent);
1522     }
1523     // pad unset mantissa
1524     if (static_cast<uint32_t>(remainMantissaBits) >= BigInt::DATEBITS) {
1525         mantissa |= (static_cast<uint64_t>(digit) << (remainMantissaBits - BigInt::DATEBITS));
1526         remainMantissaBits -= BigInt::DATEBITS;
1527         index--;
1528     }
1529     if (remainMantissaBits > 0 && index >= 0) {
1530         digit = bigint->GetDigit(index);
1531         mantissa |= (static_cast<uint64_t>(digit) >> (BigInt::DATEBITS - remainMantissaBits));
1532         remainMantissaBits -= BigInt::DATEBITS;
1533     }
1534     // After the mantissa is filled, if the bits of bigint have not been used up, consider the rounding problem
1535     // The remaining bits of the current digit
1536     if (remainMantissaBits > 0) {
1537         return CalculateNumber(sign, mantissa, exponent);
1538     }
1539     int remainDigitBits = 0;
1540     if (remainMantissaBits < 0) {
1541         remainDigitBits = -remainMantissaBits;
1542     } else {
1543         if (!index) {
1544             return CalculateNumber(sign, mantissa, exponent);
1545         }
1546         digit = bigint->GetDigit(index--);
1547         remainDigitBits = BigInt::DATEBITS;
1548     }
1549     uint32_t temp = 1ULL << (remainDigitBits - 1);
1550     if (!(digit & temp)) {
1551         return CalculateNumber(sign, mantissa, exponent);
1552     }
1553     if ((digit & (temp - 1)) != 0) {
1554         return Rounding(sign, mantissa, exponent, true);
1555     }
1556     while (index > 0) {
1557         if (bigint->GetDigit(index--) != 0) {
1558             return Rounding(sign, mantissa, exponent, true);
1559         }
1560     }
1561     return Rounding(sign, mantissa, exponent, false);
1562 }
1563 
CompareToBitsLen(JSHandle<BigInt> bigint,int numBitLen,int & leadingZeros)1564 static int CompareToBitsLen(JSHandle<BigInt> bigint, int numBitLen, int &leadingZeros)
1565 {
1566     uint32_t bigintLen = bigint->GetLength();
1567     uint32_t BigintHead = bigint->GetDigit(bigintLen - 1);
1568     leadingZeros = static_cast<int>(base::CountLeadingZeros(BigintHead));
1569     int bigintBitLen = static_cast<int>(bigintLen * BigInt::DATEBITS) - leadingZeros;
1570     bool bigintSign = bigint->GetSign();
1571     if (bigintBitLen > numBitLen) {
1572         return bigintSign ? 0 : 1;
1573     }
1574 
1575     if (bigintBitLen < numBitLen) {
1576         return bigintSign ? 1 : 0;
1577     }
1578     return -1;
1579 }
1580 
CompareWithNumber(JSHandle<BigInt> bigint,JSHandle<JSTaggedValue> number)1581 ComparisonResult BigInt::CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number)
1582 {
1583     double num = number->GetNumber();
1584     bool numberSign = num < 0;
1585     if (std::isnan(num)) {
1586         return ComparisonResult::UNDEFINED;
1587     }
1588     if (!std::isfinite(num)) {
1589         return (!numberSign ?  ComparisonResult::LESS : ComparisonResult::GREAT);
1590     }
1591     // Bit operations must be of integer type
1592     uint64_t bits = 0;
1593     if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) {
1594         LOG_FULL(FATAL) << "memcpy_s failed";
1595         UNREACHABLE();
1596     }
1597     int exponential = (bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FF;
1598 
1599     // Take out bits 62-52 (11 bits in total) and subtract 1023
1600     int integerDigits = exponential - base::DOUBLE_EXPONENT_BIAS;
1601     uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT;
1602     bool bigintSign = bigint->GetSign();
1603     // Handling the opposite sign
1604     if (!numberSign && bigintSign) {
1605         return ComparisonResult::LESS;
1606     } else if (numberSign && !bigintSign) {
1607         return ComparisonResult::GREAT;
1608     }
1609     if (bigint->IsZero() && !num) {
1610         return ComparisonResult::EQUAL;
1611     }
1612     if (bigint->IsZero() && num > 0) {
1613         return ComparisonResult::LESS;
1614     }
1615 
1616     if (integerDigits < 0) {
1617         return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
1618     }
1619 
1620     // Compare the significant bits of bigint with the significant integer bits of double
1621     int leadingZeros = 0;
1622     int res =  CompareToBitsLen(bigint, integerDigits + 1, leadingZeros);
1623     if (res == 0) {
1624         return ComparisonResult::LESS;
1625     } else if (res == 1) {
1626         return ComparisonResult::GREAT;
1627     }
1628     int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE; // mantissaSize
1629     uint32_t bigintLen = bigint->GetLength();
1630     int leftover = 0;
1631     bool IsFirstInto = true;
1632     for (int index = static_cast<int>(bigintLen - 1); index >= 0; --index) {
1633         uint32_t doubleNum = 0;
1634         uint32_t BigintNum = bigint->GetDigit(index);
1635         if (IsFirstInto) {
1636             IsFirstInto = false;
1637             leftover = mantissaSize - BigInt::DATEBITS + leadingZeros + 1;
1638             doubleNum = static_cast<uint32_t>(mantissa >> leftover);
1639             mantissa = mantissa << (64 - leftover); // 64 : double bits
1640             if (BigintNum > doubleNum) {
1641                 return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
1642             }
1643             if (BigintNum < doubleNum) {
1644                 return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
1645             }
1646         } else {
1647             leftover -= BigInt::DATEBITS;
1648             doubleNum = static_cast<uint32_t>(mantissa >> BigInt::DATEBITS);
1649             mantissa = mantissa << BigInt::DATEBITS;
1650             if (BigintNum > doubleNum) {
1651                 return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
1652             }
1653             if (BigintNum < doubleNum) {
1654                 return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
1655             }
1656             leftover -= BigInt::DATEBITS;
1657         }
1658     }
1659 
1660     if (mantissa != 0) {
1661         ASSERT(leftover > 0);
1662         return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
1663     }
1664     return ComparisonResult::EQUAL;
1665 }
1666 } // namespace
1667