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