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