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