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