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