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