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