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