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