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