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/base/number_helper.h"
18 #include "ecmascript/tagged_array-inl.h"
19 #include "object_factory.h"
20 #include "securec.h"
21 namespace panda::ecmascript {
22 class ObjectFactory;
23 constexpr char dp[] = "0123456789abcdefghijklmnopqrstuvwxyz";
CharToInt(char c)24 int CharToInt(char c)
25 {
26 int 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 res;
35 }
36
Division(std::string & num,uint32_t conversionToRadix,uint32_t currentRadix,uint32_t & remain)37 std::string Division(std::string &num, uint32_t conversionToRadix, uint32_t currentRadix, uint32_t &remain)
38 {
39 ASSERT(conversionToRadix != 0);
40 int temp = 0;
41 remain = 0;
42 for (size_t i = 0; i < num.size(); i++) {
43 temp = (currentRadix * remain + CharToInt(num[i]));
44 num[i] = dp[temp / conversionToRadix];
45 remain = temp % conversionToRadix;
46 }
47 int count = 0;
48 while (num[count] == '0') {
49 count++;
50 }
51 return num.substr(count);
52 }
53
Conversion(const std::string & num,uint32_t conversionToRadix,uint32_t currentRadix)54 std::string BigIntHelper::Conversion(const std::string &num, uint32_t conversionToRadix, uint32_t currentRadix)
55 {
56 ASSERT(conversionToRadix != 0);
57 std::string newNum = num;
58 std::string res;
59 uint32_t remain = 0;
60 while (newNum.size() != 0) {
61 newNum = Division(newNum, conversionToRadix, currentRadix, remain);
62 res = dp[remain] + res;
63 }
64 return res;
65 }
66
SetBigInt(JSThread * thread,const std::string & numStr,uint32_t currentRadix)67 JSHandle<BigInt> BigIntHelper::SetBigInt(JSThread *thread, const std::string &numStr, uint32_t currentRadix)
68 {
69 int flag = 0;
70 if (numStr[0] == '-') {
71 flag = 1;
72 }
73
74 std::string binaryStr = "";
75 if (currentRadix != BigInt::BINARY) {
76 binaryStr = Conversion(numStr.substr(flag), BigInt::BINARY, currentRadix);
77 } else {
78 binaryStr = numStr.substr(flag);
79 }
80
81 JSHandle<BigInt> bigint;
82 size_t binaryStrLen = binaryStr.size();
83 size_t len = binaryStrLen / BigInt::DATEBITS;
84 size_t mod = binaryStrLen % BigInt::DATEBITS;
85 int index = 0;
86 if (mod == 0) {
87 index = len - 1;
88 bigint = BigInt::CreateBigint(thread, len);
89 } else {
90 len++;
91 index = len - 1;
92 bigint = BigInt::CreateBigint(thread, len);
93 uint32_t val = 0;
94 for (size_t i = 0; i < mod; ++i) {
95 val <<= 1;
96 val |= binaryStr[i] - '0';
97 }
98 BigInt::SetDigit(thread, bigint, index, val);
99 index--;
100 }
101 if (flag == 1) {
102 bigint->SetSign(true);
103 }
104 size_t i = mod;
105 while (i < binaryStrLen) {
106 uint32_t val = 0;
107 for (size_t j = 0; j < BigInt::DATEBITS && i < binaryStrLen; ++j, ++i) {
108 val <<= 1;
109 val |= binaryStr[i] - '0';
110 }
111 BigInt::SetDigit(thread, bigint, index, val);
112 index--;
113 }
114 return BigIntHelper::RightTruncate(thread, bigint);
115 }
116
RightTruncate(JSThread * thread,JSHandle<BigInt> x)117 JSHandle<BigInt> BigIntHelper::RightTruncate(JSThread *thread, JSHandle<BigInt> x)
118 {
119 int len = x->GetLength();
120 ASSERT(len != 0);
121 if (len == 1 && x->GetDigit(0) == 0) {
122 x->SetSign(false);
123 return x;
124 }
125 int index = len - 1;
126 if (x->GetDigit(index) != 0) {
127 return x;
128 }
129 while (index >= 0) {
130 if (x->GetDigit(index) != 0) {
131 break;
132 }
133 index--;
134 }
135 JSHandle<TaggedArray> array(thread, x->GetData());
136 if (index == -1) {
137 array->Trim(thread, 1);
138 } else {
139 array->Trim(thread, index + 1);
140 }
141 if (x->IsZero()) {
142 x->SetSign(false);
143 }
144 return x;
145 }
146
GetBinary(JSHandle<BigInt> bigint)147 std::string BigIntHelper::GetBinary(JSHandle<BigInt> bigint)
148 {
149 int index = 0;
150 int len = bigint->GetLength();
151 int strLen = BigInt::DATEBITS * len;
152 std::string res(strLen, '0');
153 int strIndex = strLen - 1;
154 while (index < len) {
155 int bityLen = BigInt::DATEBITS;
156 uint32_t val = bigint->GetDigit(index);
157 while (bityLen--) {
158 res[strIndex--] = (val & 1) + '0';
159 val = val >> 1;
160 }
161 index++;
162 }
163 size_t count = 0;
164 size_t resLen = res.size();
165 for (size_t i = 0; i < resLen; ++i) {
166 if (res[i] != '0') {
167 break;
168 }
169 count++;
170 }
171 if (count == resLen) {
172 return "0";
173 }
174 return res.substr(count);
175 }
176
GetDigit(uint32_t index) const177 uint32_t BigInt::GetDigit(uint32_t index) const
178 {
179 TaggedArray *TaggedArray = TaggedArray::Cast(GetData().GetTaggedObject());
180 JSTaggedValue digit = TaggedArray->Get(index);
181 return static_cast<uint32_t>(digit.GetInt());
182 }
183
SetDigit(JSThread * thread,JSHandle<BigInt> bigint,uint32_t index,uint32_t digit)184 void BigInt::SetDigit(JSThread* thread, JSHandle<BigInt> bigint, uint32_t index, uint32_t digit)
185 {
186 TaggedArray *TaggedArray = TaggedArray::Cast(bigint->GetData().GetTaggedObject());
187 TaggedArray->Set(thread, index, JSTaggedValue(static_cast<int32_t>(digit)));
188 }
189
GetLength() const190 uint32_t BigInt::GetLength() const
191 {
192 TaggedArray *TaggedArray = TaggedArray::Cast(GetData().GetTaggedObject());
193 return TaggedArray->GetLength();
194 }
195
CreateBigint(JSThread * thread,uint32_t size)196 JSHandle<BigInt> BigInt::CreateBigint(JSThread *thread, uint32_t size)
197 {
198 ASSERT(size < MAXSIZE);
199 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
200 JSHandle<BigInt> bigint = factory->NewBigInt();
201 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(size);
202 bigint->SetData(thread, taggedArray.GetTaggedValue());
203 return bigint;
204 }
205
Equal(const JSTaggedValue & x,const JSTaggedValue & y)206 bool BigInt::Equal(const JSTaggedValue &x, const JSTaggedValue &y)
207 {
208 // 6.1.6.2.13
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 if (x->GetSign() != y->GetSign() || x->GetLength() != y->GetLength()) {
217 return false;
218 }
219 for (uint32_t i = 0; i < x->GetLength(); ++i) {
220 if (x->GetDigit(i) != y->GetDigit(i)) {
221 return false;
222 }
223 }
224 return true;
225 }
226
SameValue(const JSTaggedValue & x,const JSTaggedValue & y)227 bool BigInt::SameValue(const JSTaggedValue &x, const JSTaggedValue &y)
228 {
229 // 6.1.6.2.14
230 return Equal(x, y);
231 }
232
SameValueZero(const JSTaggedValue & x,const JSTaggedValue & y)233 bool BigInt::SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y)
234 {
235 // 6.1.6.2.15
236 return Equal(x, y);
237 }
238
InitializationZero(JSThread * thread,JSHandle<BigInt> bigint)239 void BigInt::InitializationZero(JSThread *thread, JSHandle<BigInt> bigint)
240 {
241 uint32_t len = bigint->GetLength();
242 for (uint32_t i = 0; i < len; ++i) {
243 SetDigit(thread, bigint, i, 0);
244 }
245 }
246
BitwiseOp(JSThread * thread,Operate op,JSHandle<BigInt> x,JSHandle<BigInt> y)247 JSHandle<BigInt> BigInt::BitwiseOp(JSThread *thread, Operate op, JSHandle<BigInt> x, JSHandle<BigInt> y)
248 {
249 uint32_t maxLen = 0;
250 uint32_t minLen = 0;
251 uint32_t xlen = x->GetLength();
252 uint32_t ylen = y->GetLength();
253 if (xlen > ylen) {
254 maxLen = xlen;
255 minLen = ylen;
256 } else {
257 maxLen = ylen;
258 minLen = xlen;
259 }
260 JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, maxLen);
261 InitializationZero(thread, bigint);
262 for (size_t i = 0; i < minLen; ++i) {
263 if (op == Operate::OR) {
264 SetDigit(thread, bigint, i, x->GetDigit(i) | y->GetDigit(i));
265 } else if (op == Operate::AND) {
266 SetDigit(thread, bigint, i, x->GetDigit(i) & y->GetDigit(i));
267 } else {
268 ASSERT(op == Operate::XOR);
269 SetDigit(thread, bigint, i, x->GetDigit(i) ^ y->GetDigit(i));
270 }
271 }
272 if (op == Operate::OR || op == Operate::XOR) {
273 if (xlen > ylen) {
274 for (size_t i = ylen; i < xlen; ++i) {
275 SetDigit(thread, bigint, i, x->GetDigit(i));
276 }
277 } else if (ylen > xlen) {
278 for (size_t i = xlen; i < ylen; ++i) {
279 SetDigit(thread, bigint, i, y->GetDigit(i));
280 }
281 }
282 }
283 return BigIntHelper::RightTruncate(thread, bigint);
284 }
285
OneIsNegativeAND(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)286 JSHandle<BigInt> OneIsNegativeAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
287 {
288 y->SetSign(false);
289 JSHandle<BigInt> yVal = BigInt::BigintSubOne(thread, y);
290 y->SetSign(true);
291 uint32_t xLength = x->GetLength();
292 uint32_t yLength = yVal->GetLength();
293 uint32_t minLen = xLength;
294 if (xLength > yLength) {
295 minLen = yLength;
296 }
297 JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, xLength);
298 uint32_t i = 0;
299 while (i < minLen) {
300 uint32_t res = x->GetDigit(i) & ~(yVal->GetDigit(i));
301 BigInt::SetDigit(thread, newBigint, i, res);
302 ++i;
303 }
304 while (i < xLength) {
305 BigInt::SetDigit(thread, newBigint, i, x->GetDigit(i));
306 ++i;
307 }
308 return BigIntHelper::RightTruncate(thread, newBigint);
309 }
310
311 // 6.1.6.2.20 BigInt::bitwiseAND ( x, y )
BitwiseAND(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)312 JSHandle<BigInt> BigInt::BitwiseAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
313 {
314 if (x->GetSign() && y->GetSign()) {
315 // (-x) & (-y) == -(((x-1) | (y-1)) + 1)
316 x->SetSign(false);
317 y->SetSign(false);
318 JSHandle<BigInt> xVal = BigintSubOne(thread, x);
319 JSHandle<BigInt> yVal = BigintSubOne(thread, y);
320 x->SetSign(true);
321 y->SetSign(true);
322 JSHandle<BigInt> temp = BitwiseOp(thread, Operate::OR, xVal, yVal);
323 JSHandle<BigInt> res = BigintAddOne(thread, temp);
324 res->SetSign(true);
325 return res;
326 }
327 if (x->GetSign() != y->GetSign()) {
328 // x & (-y) == x & ~(y-1)
329 if (!x->GetSign()) {
330 return OneIsNegativeAND(thread, x, y);
331 } else {
332 return OneIsNegativeAND(thread, y, x);
333 }
334 }
335 return BitwiseOp(thread, Operate::AND, x, y);
336 }
337
OneIsNegativeXOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)338 JSHandle<BigInt> OneIsNegativeXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
339 {
340 y->SetSign(false);
341 JSHandle<BigInt> yVal = BigInt::BigintSubOne(thread, y);
342 y->SetSign(true);
343 JSHandle<BigInt> temp = BigInt::BitwiseOp(thread, Operate::XOR, x, yVal);
344 JSHandle<BigInt> res = BigInt::BigintAddOne(thread, temp);
345 res->SetSign(true);
346 return res;
347 }
348
349 // 6.1.6.2.21 BigInt::bitwiseOR ( x, y )
BitwiseXOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)350 JSHandle<BigInt> BigInt::BitwiseXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
351 {
352 if (x->GetSign() && y->GetSign()) {
353 // (-x) ^ (-y) == (x-1) ^ (y-1)
354 x->SetSign(false);
355 y->SetSign(false);
356 JSHandle<BigInt> xVal = BigintSubOne(thread, x);
357 JSHandle<BigInt> yVal = BigintSubOne(thread, y);
358 x->SetSign(true);
359 y->SetSign(true);
360 return BitwiseOp(thread, Operate::XOR, xVal, yVal);
361 }
362 if (x->GetSign() != y->GetSign()) {
363 // x ^ (-y) == -((x ^ (y-1)) + 1)
364 if (!x->GetSign()) {
365 return OneIsNegativeXOR(thread, x, y);
366 } else {
367 return OneIsNegativeXOR(thread, y, x);
368 }
369 }
370 return BitwiseOp(thread, Operate::XOR, x, y);
371 }
372
BitwiseSubOne(JSThread * thread,JSHandle<BigInt> bigint,uint32_t maxLen)373 JSHandle<BigInt> BigInt::BitwiseSubOne(JSThread *thread, JSHandle<BigInt> bigint, uint32_t maxLen)
374 {
375 ASSERT(!bigint->IsZero());
376 ASSERT(maxLen >= bigint->GetLength());
377
378 JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, maxLen);
379
380 uint32_t bigintLen = bigint->GetLength();
381 uint32_t carry = 1;
382 for (uint32_t i = 0; i < bigintLen; i++) {
383 uint32_t bigintCarry = 0;
384 BigInt::SetDigit(thread, newBigint, i, BigIntHelper::SubHelper(bigint->GetDigit(i), carry, bigintCarry));
385 carry = bigintCarry;
386 }
387 ASSERT(!carry);
388 for (uint32_t i = bigintLen; i < maxLen; i++) {
389 BigInt::SetDigit(thread, newBigint, i, carry);
390 }
391 return BigIntHelper::RightTruncate(thread, newBigint);
392 }
393
BitwiseAddOne(JSThread * thread,JSHandle<BigInt> bigint)394 JSHandle<BigInt> BigInt::BitwiseAddOne(JSThread *thread, JSHandle<BigInt> bigint)
395 {
396 uint32_t bigintLength = bigint->GetLength();
397
398 bool needExpend = true;
399 for (uint32_t i = 0; i < bigintLength; i++) {
400 if (std::numeric_limits<uint32_t>::max() != bigint->GetDigit(i)) {
401 needExpend = false;
402 break;
403 }
404 }
405 uint32_t newLength = bigintLength;
406 if (needExpend) {
407 newLength += 1;
408 }
409 JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, newLength);
410
411 uint32_t carry = 1;
412 for (uint32_t i = 0; i < bigintLength; i++) {
413 uint32_t bigintCarry = 0;
414 BigInt::SetDigit(thread, newBigint, i, BigIntHelper::AddHelper(bigint->GetDigit(i), carry, bigintCarry));
415 carry = bigintCarry;
416 }
417 if (needExpend) {
418 BigInt::SetDigit(thread, newBigint, bigintLength, carry);
419 } else {
420 ASSERT(!carry);
421 }
422 newBigint->SetSign(true);
423 return BigIntHelper::RightTruncate(thread, newBigint);
424 }
425
OneIsNegativeOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)426 JSHandle<BigInt> OneIsNegativeOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
427 {
428 uint32_t xLength = x->GetLength();
429 uint32_t maxLen = xLength;
430 if (maxLen < y->GetLength()) {
431 maxLen = y->GetLength();
432 }
433 JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, maxLen);
434 uint32_t yLength = yVal->GetLength();
435 uint32_t minLen = xLength;
436 if (minLen > yLength) {
437 minLen = yLength;
438 }
439 JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, yLength);
440 uint32_t i = 0;
441 while (i < minLen) {
442 uint32_t res = ~(x->GetDigit(i)) & yVal->GetDigit(i);
443 BigInt::SetDigit(thread, newBigint, i, res);
444 ++i;
445 }
446 while (i < yLength) {
447 BigInt::SetDigit(thread, newBigint, i, yVal->GetDigit(i));
448 ++i;
449 }
450 JSHandle<BigInt> temp = BigIntHelper::RightTruncate(thread, newBigint);
451 JSHandle<BigInt> res = BigInt::BitwiseAddOne(thread, temp);
452 res->SetSign(true);
453 return res;
454 }
455
456 // 6.1.6.2.22 BigInt::bitwiseOR ( x, y )
BitwiseOR(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)457 JSHandle<BigInt> BigInt::BitwiseOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
458 {
459 if (x->GetSign() && y->GetSign()) {
460 // (-x) | (-y) == -(((x-1) & (y-1)) + 1)
461 uint32_t maxLen = x->GetLength();
462 uint32_t yLen = y->GetLength();
463 maxLen < yLen ? maxLen = yLen : 0;
464 JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, maxLen);
465 JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, yLen);
466 JSHandle<BigInt> temp = BitwiseOp(thread, Operate::AND, xVal, yVal);
467 JSHandle<BigInt> res = BitwiseAddOne(thread, temp);
468 res->SetSign(true);
469 return res;
470 }
471 if (x->GetSign() != y->GetSign()) {
472 // x | (-y) == -(((y-1) & ~x) + 1)
473 if (!x->GetSign()) {
474 return OneIsNegativeOR(thread, x, y);
475 } else {
476 return OneIsNegativeOR(thread, y, x);
477 }
478 }
479 return BitwiseOp(thread, Operate::OR, x, y);
480 }
481
ToString(JSThread * thread,JSHandle<BigInt> bigint,uint32_t conversionToRadix)482 JSHandle<EcmaString> BigInt::ToString(JSThread *thread, JSHandle<BigInt> bigint, uint32_t conversionToRadix)
483 {
484 // 6.1.6.2.23 BigInt::toString ( x )
485 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
486 std::string result =
487 BigIntHelper::Conversion(BigIntHelper::GetBinary(bigint), conversionToRadix, BigInt::BINARY);
488 if (bigint->GetSign() && !(result.size() == 1 && result[0] == '0')) {
489 result = "-" + result;
490 }
491 return factory->NewFromStdStringUnCheck(result, true);
492 }
493
ToStdString(JSThread * thread,JSHandle<BigInt> bigint,uint32_t conversionToRadix)494 std::string BigInt::ToStdString(JSThread *thread, JSHandle<BigInt> bigint, uint32_t conversionToRadix)
495 {
496 std::string result =
497 BigIntHelper::Conversion(BigIntHelper::GetBinary(bigint), conversionToRadix, BigInt::BINARY);
498 if (bigint->GetSign() && !(result.size() == 1 && result[0] == '0')) {
499 result = "-" + result;
500 }
501 return result;
502 }
503
NumberToBigInt(JSThread * thread,JSHandle<JSTaggedValue> number)504 JSTaggedValue BigInt::NumberToBigInt(JSThread *thread, JSHandle<JSTaggedValue> number)
505 {
506 if (!number->IsInteger()) {
507 THROW_RANGE_ERROR_AND_RETURN(thread, "The number cannot be converted to a BigInt because it is not an integer",
508 JSTaggedValue::Exception());
509 }
510 double num = number->GetNumber();
511 if (num == 0.0) {
512 return Int32ToBigInt(thread, 0).GetTaggedValue();
513 }
514
515 // Bit operations must be of integer type
516 uint64_t bits = 0;
517 if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) {
518 LOG_ECMA(FATAL) << "memset_s failed";
519 UNREACHABLE();
520 }
521 // Take out bits 62-52 (11 bits in total) and subtract 1023
522 uint64_t integerDigits = ((bits >> 52) & 0x7FF) - 0x3FF; // 52 : mantissa size
523 uint32_t MayNeedLen = integerDigits / BigInt::DATEBITS + 1;
524
525 JSHandle<BigInt> bigint = CreateBigint(thread, MayNeedLen);
526 bigint->SetSign(num < 0);
527 uint64_t mantissa = (bits & 0x000FFFFFFFFFFFFF) | 0x0010000000000000;
528 int mantissaSize = 52; // mantissaSize
529
530 int leftover = 0;
531 bool IsFirstInto = true;
532 for (int index = MayNeedLen - 1; index >= 0; --index) {
533 uint32_t doubleNum = 0;
534 if (IsFirstInto) {
535 IsFirstInto = false;
536 leftover = mantissaSize - (integerDigits % BigInt::DATEBITS);
537 doubleNum = static_cast<uint32_t>(mantissa >> leftover);
538 mantissa = mantissa << (64 - leftover); // 64 : double bits size
539 BigInt::SetDigit(thread, bigint, index, doubleNum);
540 } else {
541 leftover -= BigInt::DATEBITS;
542 doubleNum = static_cast<uint32_t>(mantissa >> BigInt::DATEBITS);
543 mantissa = mantissa << BigInt::DATEBITS;
544 BigInt::SetDigit(thread, bigint, 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 return BigIntHelper::SetBigInt(thread, std::to_string(number));
553 }
554
Int64ToBigInt(JSThread * thread,const int64_t & number)555 JSHandle<BigInt> BigInt::Int64ToBigInt(JSThread *thread, const int64_t &number)
556 {
557 return BigIntHelper::SetBigInt(thread, std::to_string(number));
558 }
559
Uint64ToBigInt(JSThread * thread,const uint64_t & number)560 JSHandle<BigInt> BigInt::Uint64ToBigInt(JSThread *thread, const uint64_t &number)
561 {
562 return BigIntHelper::SetBigInt(thread, std::to_string(number));
563 }
564
BigIntToInt64(JSThread * thread,JSHandle<JSTaggedValue> bigint,int64_t * cValue,bool * lossless)565 void BigInt::BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless)
566 {
567 ASSERT(bigint->IsBigInt());
568 ASSERT(cValue);
569 ASSERT(lossless);
570 JSHandle<BigInt> bigInt64(thread, JSTaggedValue::ToBigInt64(thread, bigint));
571 if (Equal(bigInt64.GetTaggedValue(), bigint.GetTaggedValue())) {
572 *lossless = true;
573 }
574 uint32_t *addr = reinterpret_cast<uint32_t *>(cValue);
575 int len = bigInt64->GetLength();
576 for (int index = len - 1; index >= 0; --index) {
577 *(addr + index) = bigInt64->GetDigit(index);
578 }
579 if (bigInt64->GetSign()) {
580 *cValue = ~(*cValue - 1);
581 }
582 }
583
BigIntToUint64(JSThread * thread,JSHandle<JSTaggedValue> bigint,uint64_t * cValue,bool * lossless)584 void BigInt::BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless)
585 {
586 ASSERT(bigint->IsBigInt());
587 ASSERT(cValue);
588 ASSERT(lossless);
589 JSHandle<BigInt> bigUint64(thread, JSTaggedValue::ToBigUint64(thread, bigint));
590 if (Equal(bigUint64.GetTaggedValue(), bigint.GetTaggedValue())) {
591 *lossless = true;
592 }
593 uint32_t *addr = reinterpret_cast<uint32_t *>(cValue);
594 int len = bigUint64->GetLength();
595 for (int index = len - 1; index >= 0; --index) {
596 *(addr + index) = bigUint64->GetDigit(index);
597 }
598 }
599
CreateBigWords(JSThread * thread,bool sign,uint32_t size,const uint64_t * words)600 JSHandle<BigInt> BigInt::CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t* words)
601 {
602 uint32_t needLen = size * 2; // 2 : uint64_t size to uint32_t size
603 JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
604 const uint32_t *digits = reinterpret_cast<const uint32_t *>(words);
605 for (uint32_t index = 0; index < needLen; ++index) {
606 SetDigit(thread, bigint, index, *(digits + index));
607 }
608 bigint->SetSign(sign);
609 return BigIntHelper::RightTruncate(thread, bigint);
610 }
611
Add(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)612 JSHandle<BigInt> BigInt::Add(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
613 {
614 bool xSignFlag = x->GetSign();
615 bool ySignFlag = y->GetSign();
616 // x + y == x + y
617 // -x + -y == -(x + y)
618 if (xSignFlag == ySignFlag) {
619 return BigintAdd(thread, x, y, xSignFlag);
620 }
621 // x + -y == x - y == -(y - x)
622 // -x + y == y - x == -(x - y)
623 uint32_t xLength = x->GetLength();
624 uint32_t yLength = y->GetLength();
625 uint32_t i = xLength - 1;
626 int subSize = xLength - yLength;
627 if (subSize > 0) {
628 return BigintSub(thread, x, y, xSignFlag);
629 } else if (subSize == 0) {
630 while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
631 i--;
632 }
633 if ((x->GetDigit(i) > y->GetDigit(i))) {
634 return BigintSub(thread, x, y, xSignFlag);
635 } else {
636 return BigintSub(thread, y, x, ySignFlag);
637 }
638 } else {
639 return BigintSub(thread, y, x, ySignFlag);
640 }
641 }
Subtract(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)642 JSHandle<BigInt> BigInt::Subtract(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
643 {
644 bool xSignFlag = x->GetSign();
645 bool ySignFlag = y->GetSign();
646 if (xSignFlag != ySignFlag) {
647 // x - (-y) == x + y
648 // (-x) - y == -(x + y)
649 return BigintAdd(thread, x, y, xSignFlag);
650 }
651 // x - y == -(y - x)
652 // (-x) - (-y) == y - x == -(x - y)
653 uint32_t xLength = x->GetLength();
654 uint32_t yLength = y->GetLength();
655 uint32_t i = xLength - 1;
656 int subSize = xLength - yLength;
657 if (subSize > 0) {
658 return BigintSub(thread, x, y, xSignFlag);
659 } else if (subSize == 0) {
660 while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
661 i--;
662 }
663 if ((x->GetDigit(i) > y->GetDigit(i))) {
664 return BigintSub(thread, x, y, xSignFlag);
665 } else {
666 return BigintSub(thread, y, x, !ySignFlag);
667 }
668 } else {
669 return BigintSub(thread, y, x, !ySignFlag);
670 }
671 }
672
BigintAdd(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y,bool resultSign)673 JSHandle<BigInt> BigInt::BigintAdd(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign)
674 {
675 if (x->GetLength() < y->GetLength()) {
676 return BigintAdd(thread, y, x, resultSign);
677 }
678 JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength() + 1);
679 uint32_t bigintCarry = 0;
680 uint32_t i = 0;
681 while (i < y->GetLength()) {
682 uint32_t newBigintCarry = 0;
683 uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry);
684 addPlus = BigIntHelper::AddHelper(addPlus, bigintCarry, newBigintCarry);
685 SetDigit(thread, bigint, i, addPlus);
686 bigintCarry = newBigintCarry;
687 i++;
688 }
689 while (i < x->GetLength()) {
690 uint32_t newBigintCarry = 0;
691 uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
692 SetDigit(thread, bigint, i, addPlus);
693 bigintCarry = newBigintCarry;
694 i++;
695 }
696 SetDigit(thread, bigint, i, bigintCarry);
697 bigint->SetSign(resultSign);
698 return BigIntHelper::RightTruncate(thread, bigint);
699 }
700
AddHelper(uint32_t x,uint32_t y,uint32_t & bigintCarry)701 inline uint32_t BigIntHelper::AddHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry)
702 {
703 uint32_t addPlus = x + y;
704 if (addPlus < x) {
705 bigintCarry += 1;
706 }
707 return addPlus;
708 }
709
BigintSub(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y,bool resultSign)710 JSHandle<BigInt> BigInt::BigintSub(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign)
711 {
712 JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength());
713 uint32_t bigintCarry = 0;
714 uint32_t i = 0;
715 while (i < y->GetLength()) {
716 uint32_t newBigintCarry = 0;
717 uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry);
718 minuSub = BigIntHelper::SubHelper(minuSub, bigintCarry, newBigintCarry);
719 SetDigit(thread, bigint, i, minuSub);
720 bigintCarry = newBigintCarry;
721 i++;
722 }
723 while (i < x->GetLength()) {
724 uint32_t newBigintCarry = 0;
725 uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
726 SetDigit(thread, bigint, i, minuSub);
727 bigintCarry = newBigintCarry;
728 i++;
729 }
730 bigint->SetSign(resultSign);
731 return BigIntHelper::RightTruncate(thread, bigint);
732 }
733
BigintAddOne(JSThread * thread,JSHandle<BigInt> x)734 JSHandle<BigInt> BigInt::BigintAddOne(JSThread *thread, JSHandle<BigInt> x)
735 {
736 JSHandle<BigInt> temp = Int32ToBigInt(thread, 1);
737 return Add(thread, x, temp);
738 }
739
BigintSubOne(JSThread * thread,JSHandle<BigInt> x)740 JSHandle<BigInt> BigInt::BigintSubOne(JSThread *thread, JSHandle<BigInt> x)
741 {
742 JSHandle<BigInt> temp = Int32ToBigInt(thread, 1);
743 return Subtract(thread, x, temp);
744 }
745
SubHelper(uint32_t x,uint32_t y,uint32_t & bigintCarry)746 inline uint32_t BigIntHelper::SubHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry)
747 {
748 uint32_t minuSub = x - y;
749 if (minuSub > x) {
750 bigintCarry += 1;
751 }
752 return minuSub;
753 }
754
Compare(JSThread * thread,const JSTaggedValue & x,const JSTaggedValue & y)755 ComparisonResult BigInt::Compare(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y)
756 {
757 if (!LessThan(x, y)) {
758 if (!LessThan(y, x)) {
759 return ComparisonResult::EQUAL;
760 }
761 return ComparisonResult::GREAT;
762 }
763 return ComparisonResult::LESS;
764 }
765
LessThan(const JSTaggedValue & x,const JSTaggedValue & y)766 bool BigInt::LessThan(const JSTaggedValue &x, const JSTaggedValue &y)
767 {
768 BigInt* xVal = BigInt::Cast(x.GetTaggedObject());
769 BigInt* yVal = BigInt::Cast(y.GetTaggedObject());
770 return LessThan(xVal, yVal);
771 }
772
LessThan(const BigInt * x,const BigInt * y)773 bool BigInt::LessThan(const BigInt *x, const BigInt *y)
774 {
775 bool xSignFlag = x->GetSign();
776 bool ySignFlag = y->GetSign();
777 int minSize = x->GetLength() - y->GetLength();
778 uint32_t i = x->GetLength() - 1;
779 if (xSignFlag != ySignFlag) {
780 return xSignFlag ? true : false;
781 } else {
782 if (minSize != 0 && xSignFlag) {
783 return minSize > 0 ? true : false;
784 }
785 if (minSize != 0 && !xSignFlag) {
786 return minSize > 0 ? false : true;
787 }
788 while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
789 i--;
790 }
791 if ((x->GetDigit(i) > y->GetDigit(i))) {
792 return xSignFlag ? true : false;
793 } else if ((x->GetDigit(i) < y->GetDigit(i))) {
794 return !xSignFlag ? true : false;
795 } else {
796 return false;
797 }
798 }
799 }
800
SignedRightShift(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)801 JSHandle<BigInt> BigInt::SignedRightShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
802 {
803 bool xIsNull = x->GetDigit(0);
804 bool yIsNull = y->GetDigit(0);
805 if (!xIsNull || !yIsNull) {
806 return x;
807 }
808 if (y->GetSign()) {
809 return LeftShiftHelper(thread, x, y);
810 } else {
811 return RightShiftHelper(thread, x, y);
812 }
813 }
814
RightShiftHelper(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)815 JSHandle<BigInt> BigInt::RightShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
816 {
817 std::string shiftBinay = BigIntHelper::GetBinary(x);
818 std::string revTemp = std::string(shiftBinay.rbegin(), shiftBinay.rend());
819 for (uint32_t i = 0; i < y->GetLength(); i++) {
820 revTemp = revTemp.erase(0, y->GetDigit(i));
821 }
822 std::string finalBinay = std::string(revTemp.rbegin(), revTemp.rend());
823 if (finalBinay.empty()) {
824 finalBinay = "0";
825 }
826 JSHandle<BigInt> bigint = BigIntHelper::SetBigInt(thread, finalBinay, BINARY);
827 if (x->GetSign()) {
828 SetDigit(thread, bigint, 0, bigint->GetDigit(0) + 1);
829 }
830 bigint->SetSign(x->GetSign());
831 return BigIntHelper::RightTruncate(thread, bigint);
832 }
833
LeftShift(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)834 JSHandle<BigInt> BigInt::LeftShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
835 {
836 if (y->GetSign()) {
837 return RightShiftHelper(thread, x, y);
838 } else {
839 return LeftShiftHelper(thread, x, y);
840 }
841 }
842
LeftShiftHelper(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)843 JSHandle<BigInt> BigInt::LeftShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
844 {
845 std::string shiftBinay = BigIntHelper::GetBinary(x);
846 for (size_t i = 0; i < y->GetLength(); i++) {
847 shiftBinay = shiftBinay.append(y->GetDigit(i), '0');
848 }
849 JSHandle<BigInt> bigint = BigIntHelper::SetBigInt(thread, shiftBinay, BINARY);
850 bigint->SetSign(x->GetSign());
851 return BigIntHelper::RightTruncate(thread, bigint);
852 }
853
UnsignedRightShift(JSThread * thread)854 JSTaggedValue BigInt::UnsignedRightShift(JSThread *thread)
855 {
856 THROW_TYPE_ERROR_AND_RETURN(thread, "BigInts have no unsigned right shift, use >> instead",
857 JSTaggedValue::Exception());
858 }
859
copy(JSThread * thread,JSHandle<BigInt> x)860 JSHandle<BigInt> BigInt::copy(JSThread *thread, JSHandle<BigInt> x)
861 {
862 uint32_t len = x->GetLength();
863 JSHandle<BigInt> temp = CreateBigint(thread, len);
864 for (uint32_t i = 0; i < len; i++) {
865 SetDigit(thread, temp, i, x->GetDigit(i));
866 }
867 temp->SetSign(x->GetSign());
868 return temp;
869 }
870
UnaryMinus(JSThread * thread,JSHandle<BigInt> x)871 JSHandle<BigInt> BigInt::UnaryMinus(JSThread *thread, JSHandle<BigInt> x)
872 {
873 if (x->IsZero()) {
874 return x;
875 }
876 JSHandle<BigInt> y = copy(thread, x);
877 y->SetSign(!y->GetSign());
878 return y;
879 }
880
BitwiseNOT(JSThread * thread,JSHandle<BigInt> x)881 JSHandle<BigInt> BigInt::BitwiseNOT(JSThread *thread, JSHandle<BigInt> x)
882 {
883 // 6.1.6.2.2 BigInt::bitwiseNOT ( x )
884 // ~(-x) == ~(~(x-1)) == x-1
885 // ~x == -x-1 == -(x+1)
886 JSHandle<BigInt> result = BigintAddOne(thread, x);
887 if (x->GetSign()) {
888 result->SetSign(false);
889 } else {
890 result->SetSign(true);
891 }
892 return result;
893 }
894
Exponentiate(JSThread * thread,JSHandle<BigInt> base,JSHandle<BigInt> exponent)895 JSHandle<BigInt> BigInt::Exponentiate(JSThread *thread, JSHandle<BigInt> base, JSHandle<BigInt> exponent)
896 {
897 if (exponent->GetSign()) {
898 JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
899 THROW_RANGE_ERROR_AND_RETURN(thread, "Exponent must be positive", bigint);
900 }
901 ASSERT(exponent->GetLength() == 1);
902 if (exponent->IsZero()) {
903 return BigIntHelper::SetBigInt(thread, "1");
904 }
905
906 if (base->IsZero()) {
907 return BigIntHelper::SetBigInt(thread, "0");
908 }
909 uint32_t EValue = exponent->GetDigit(0);
910 if (EValue == 1) {
911 return base;
912 }
913 uint32_t j = exponent->GetDigit(0) - 1;
914 std::string a = BigIntHelper::GetBinary(base);
915 a = BigIntHelper::Conversion(a, DECIMAL, BINARY);
916 std::string b = a;
917 for (uint32_t i = 0; i < j; ++i) {
918 b = BigIntHelper::MultiplyImpl(b, a);
919 }
920 if (exponent->GetDigit(0) & 1) {
921 if (base->GetSign()) {
922 b = "-" + b;
923 }
924 }
925 return BigIntHelper::SetBigInt(thread, b, DECIMAL);
926 }
MultiplyImpl(std::string & a,std::string & b)927 std::string BigIntHelper::MultiplyImpl(std::string &a, std::string &b)
928 {
929 int size1 = a.size();
930 int size2 = b.size();
931 std::string str(size1 + size2, '0');
932 for (int i = size2 - 1; i >= 0; --i) {
933 int mulflag = 0;
934 int addflag = 0;
935 for (int j = size1 - 1; j >= 0; --j) {
936 int temp1 = (b[i] - '0') * (a[j] - '0') + mulflag;
937 mulflag = temp1 / 10; // 10:help to Remove single digits
938 temp1 = temp1 % 10; // 10:help to Take single digit
939 int temp2 = str[i + j + 1] - '0' + temp1 + addflag;
940 str[i + j + 1] = temp2 % 10 + 48; // 2 and 10 and 48 is number
941 addflag = temp2 / 10;
942 }
943 str[i] += mulflag + addflag;
944 }
945 if (str[0] == '0') {
946 str = str.substr(1, str.size());
947 }
948 return str;
949 }
950
Multiply(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)951 JSHandle<BigInt> BigInt::Multiply(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
952 {
953 if (x->IsZero()) {
954 return x;
955 }
956 if (y->IsZero()) {
957 return y;
958 }
959 std::string left = BigIntHelper::GetBinary(x);
960 std::string right = BigIntHelper::GetBinary(y);
961 left = BigIntHelper::Conversion(left, DECIMAL, BINARY);
962 right = BigIntHelper::Conversion(right, DECIMAL, BINARY);
963 std::string ab = BigIntHelper::MultiplyImpl(left, right);
964 if (x->GetSign() != y->GetSign()) {
965 ab = "-" + ab;
966 }
967 return BigIntHelper::SetBigInt(thread, ab, DECIMAL);
968 }
969
DeZero(std::string & a)970 std::string BigIntHelper::DeZero(std::string &a)
971 {
972 size_t i;
973 for (i = 0; i < a.length(); i++) {
974 if (a.at(i) > 48) { // 48 is ascill of '0'
975 break;
976 }
977 }
978 if (i == a.length()) {
979 return "0";
980 }
981 a.erase(0, i);
982 return a;
983 }
984
ComString(std::string & a,std::string & b)985 Comparestr BigInt::ComString(std::string &a, std::string &b)
986 {
987 if (a.length() > b.length()) {
988 return Comparestr::GREATER;
989 }
990 if (a.length() < b.length()) {
991 return Comparestr::LESS;
992 }
993 for (size_t i = 0; i < a.length(); i++) {
994 if (a.at(i) > b.at(i)) {
995 return Comparestr::GREATER;
996 }
997 if (a.at(i) < b.at(i)) {
998 return Comparestr::LESS;
999 }
1000 }
1001 return Comparestr::EQUAL;
1002 }
1003
DevStr(std::string & strValue)1004 std::string BigIntHelper::DevStr(std::string &strValue)
1005 {
1006 size_t i = 0;
1007 for (i = 0; i < strValue.length(); i++) {
1008 if (strValue.at(i) >= 48 && strValue.at(i) <= 57) { // 48 and 57 is '0' and '9'
1009 strValue.at(i) -= 48; // 48:'0'
1010 }
1011 if (strValue.at(i) >= 97 && strValue.at(i) <= 122) { // 97 and 122 is 'a' and 'z'
1012 strValue.at(i) -= 87; // 87 control result is greater than 10
1013 }
1014 }
1015 return strValue;
1016 }
1017
Minus(std::string & a,std::string & b)1018 std::string BigIntHelper::Minus(std::string &a, std::string &b)
1019 {
1020 a = DeZero(a);
1021 b = DeZero(b);
1022 size_t i = 0;
1023 int j = 0;
1024 std::string res = "0";
1025 std::string result1;
1026 std::string result2;
1027 std::string dsymbol = "-";
1028 if (BigInt::ComString(a, b) == Comparestr::EQUAL) {
1029 return res;
1030 }
1031 if (BigInt::ComString(a, b) == Comparestr::GREATER) {
1032 result1 = a;
1033 result2 = b;
1034 }
1035 if (BigInt::ComString(a, b) == Comparestr::LESS) {
1036 result1 = b;
1037 result2 = a;
1038 j = -1;
1039 }
1040 reverse(result1.begin(), result1.end());
1041 reverse(result2.begin(), result2.end());
1042 result1 = DevStr(result1);
1043 result2 = DevStr(result2);
1044 for (i = 0; i < result2.length(); i++) {
1045 result1.at(i) = result1.at(i) - result2.at(i);
1046 }
1047 for (i = 0; i < result1.length() - 1; i++) {
1048 if (result1.at(i) < 0) {
1049 result1.at(i) += BigInt::DECIMAL;
1050 result1.at(i + 1)--;
1051 }
1052 }
1053 for (i = result1.length() - 1; i >= 0; i--) {
1054 if (result1.at(i) > 0) {
1055 break;
1056 }
1057 }
1058 result1.erase(i + 1, result1.length());
1059 for (i = 0; i < result1.length(); i++) {
1060 if (result1.at(i) >= 10) { // 10:Hexadecimal a
1061 result1.at(i) += 87; // 87:control result is greater than 97
1062 }
1063 if (result1.at(i) < 10) { // 10: 10:Hexadecimal a
1064 result1.at(i) += 48; // 48:'0'
1065 }
1066 }
1067 reverse(result1.begin(), result1.end());
1068 if (j == -1) {
1069 result1.insert(0, dsymbol);
1070 }
1071 return result1;
1072 }
1073
Divide(std::string & a,std::string & b)1074 std::string BigIntHelper::Divide(std::string &a, std::string &b)
1075 {
1076 size_t i = 0;
1077 size_t j = 0;
1078 std::string result1;
1079 std::string result2;
1080 std::string dsy;
1081 std::string quotient;
1082 if (BigInt::ComString(a, b) == Comparestr::EQUAL) {
1083 return "1";
1084 }
1085 if (BigInt::ComString(a, b) == Comparestr::LESS) {
1086 return "0";
1087 }
1088 result1 = DeZero(a);
1089 result2 = DeZero(b);
1090 dsy = "";
1091 quotient = "";
1092 for (i = 0; i < result1.length(); i++) {
1093 j = 0;
1094 dsy = dsy + result1.at(i);
1095 dsy = DeZero(dsy);
1096 while (BigInt::ComString(dsy, b) == Comparestr::EQUAL ||
1097 BigInt::ComString(dsy, b) == Comparestr::GREATER) {
1098 dsy = Minus(dsy, b);
1099 dsy = DeZero(dsy);
1100 j++;
1101 }
1102 quotient = quotient + "0";
1103 quotient.at(i) = j;
1104 }
1105 for (i = 0; i < quotient.length(); i++) {
1106 if (quotient.at(i) >= 10) { // 10 is number
1107 quotient.at(i) += 87; // 87 is number
1108 }
1109 if (quotient.at(i) < 10) { // 10 is number
1110 quotient.at(i) += 48; // 48 is number
1111 }
1112 }
1113 quotient = DeZero(quotient);
1114 return quotient;
1115 }
1116
DivideImpl(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)1117 JSHandle<BigInt> BigIntHelper::DivideImpl(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
1118 {
1119 std::string a = Conversion(GetBinary(x), BigInt::DECIMAL, BigInt::BINARY);
1120 std::string b = Conversion(GetBinary(y), BigInt::DECIMAL, BigInt::BINARY);
1121 std::string ab = Divide(a, b);
1122 if (ab == "0") {
1123 ab = "0";
1124 } else if (x->GetSign() != y->GetSign()) {
1125 ab = "-" + ab;
1126 }
1127 return SetBigInt(thread, ab, BigInt::DECIMAL);
1128 }
1129
Divide(JSThread * thread,JSHandle<BigInt> x,JSHandle<BigInt> y)1130 JSHandle<BigInt> BigInt::Divide(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
1131 {
1132 if (y->IsZero()) {
1133 JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
1134 THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint);
1135 }
1136 return BigIntHelper::DivideImpl(thread, x, y);
1137 }
1138
1139
Remainder(JSThread * thread,JSHandle<BigInt> n,JSHandle<BigInt> d)1140 JSHandle<BigInt> BigInt::Remainder(JSThread *thread, JSHandle<BigInt> n, JSHandle<BigInt> d)
1141 {
1142 if (d->IsZero()) {
1143 JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
1144 THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint);
1145 }
1146 if (n->IsZero()) {
1147 return n;
1148 }
1149 JSHandle<BigInt> q = Divide(thread, n, d);
1150 JSHandle<BigInt> p = Multiply(thread, q, d);
1151 return Subtract(thread, n, p);
1152 }
1153
FloorMod(JSThread * thread,JSHandle<BigInt> leftVal,JSHandle<BigInt> rightVal)1154 JSHandle<BigInt> BigInt::FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal)
1155 {
1156 if (leftVal->GetSign()) {
1157 JSHandle<BigInt> quotientVal = Divide(thread, leftVal, rightVal);
1158 if (quotientVal->IsZero()) {
1159 return Add(thread, leftVal, rightVal);
1160 } else {
1161 JSHandle<BigInt> num = Multiply(thread, quotientVal, rightVal);
1162 if (Equal(num.GetTaggedValue(), leftVal.GetTaggedValue())) {
1163 return Int32ToBigInt(thread, 0);
1164 } else {
1165 return Subtract(thread, leftVal, Subtract(thread, num, rightVal));
1166 }
1167 }
1168 }
1169 return Remainder(thread, leftVal, rightVal);
1170 }
1171
AsUintN(JSThread * thread,JSTaggedNumber & bits,JSHandle<BigInt> bigint)1172 JSTaggedValue BigInt::AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint)
1173 {
1174 uint32_t bit = bits.ToUint32();
1175 if (bit == 0) {
1176 return Int32ToBigInt(thread, 0).GetTaggedValue();
1177 }
1178 if (bigint->IsZero()) {
1179 return bigint.GetTaggedValue();
1180 }
1181 JSHandle<BigInt> exponent = Int32ToBigInt(thread, bit);
1182 JSHandle<BigInt> base = Int32ToBigInt(thread, 2); // 2 : base value
1183 JSHandle<BigInt> tValue = Exponentiate(thread, base, exponent);
1184 return FloorMod(thread, bigint, tValue).GetTaggedValue();
1185 }
1186
AsintN(JSThread * thread,JSTaggedNumber & bits,JSHandle<BigInt> bigint)1187 JSTaggedValue BigInt::AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint)
1188 {
1189 uint32_t bit = bits.ToUint32();
1190 if (bit == 0) {
1191 return Int32ToBigInt(thread, 0).GetTaggedValue();
1192 }
1193 if (bigint->IsZero()) {
1194 return bigint.GetTaggedValue();
1195 }
1196 JSHandle<BigInt> exp = Int32ToBigInt(thread, bit);
1197 JSHandle<BigInt> exponent = Int32ToBigInt(thread, bit - 1);
1198 JSHandle<BigInt> base = Int32ToBigInt(thread, 2); // 2 : base value
1199 JSHandle<BigInt> tValue = Exponentiate(thread, base, exp);
1200 JSHandle<BigInt> modValue = FloorMod(thread, bigint, tValue);
1201 JSHandle<BigInt> resValue = Exponentiate(thread, base, exponent);
1202 // If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return (mod).
1203 if (LessThan(resValue.GetTaggedValue(), modValue.GetTaggedValue()) ||
1204 Equal(resValue.GetTaggedValue(), modValue.GetTaggedValue())) {
1205 return Subtract(thread, modValue, tValue).GetTaggedValue();
1206 }
1207 return modValue.GetTaggedValue();
1208 }
1209
BigIntToNumber(JSThread * thread,JSHandle<BigInt> bigint)1210 JSTaggedNumber BigInt::BigIntToNumber(JSThread *thread, JSHandle<BigInt> bigint)
1211 {
1212 std::string bigintStr = ToStdString(thread, bigint, HEXADECIMAL);
1213 bool sign = false;
1214 if (bigintStr[0] == '-') {
1215 bigintStr = bigintStr.substr(1); // 1 : dump '-'
1216 sign = true;
1217 }
1218 bigintStr = "0x" + bigintStr;
1219 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1220 JSHandle<EcmaString> str = factory->NewFromStdStringUnCheck(bigintStr, true);
1221 JSHandle<JSTaggedValue> numberStr(thread, str.GetTaggedValue());
1222 JSTaggedNumber number = JSTaggedValue::ToNumber(thread, numberStr);
1223 if (sign) {
1224 return JSTaggedNumber(-number.GetNumber());
1225 }
1226 return number;
1227 }
1228
CompareToBitsLen(JSHandle<BigInt> bigint,int numBitLen,int & preZero)1229 int CompareToBitsLen(JSHandle<BigInt> bigint, int numBitLen, int &preZero)
1230 {
1231 uint32_t bigintLen = bigint->GetLength();
1232 uint32_t BigintHead = bigint->GetDigit(bigintLen - 1);
1233 uint32_t bits = BigInt::DATEBITS;
1234 while (bits) {
1235 bits--;
1236 if (((BigintHead >> bits) | 0) != 0) {
1237 break;
1238 }
1239 preZero++;
1240 }
1241
1242 int bigintBitLen = bigintLen * BigInt::DATEBITS - preZero;
1243 bool bigintSign = bigint->GetSign();
1244 if (bigintBitLen > numBitLen) {
1245 return bigintSign ? 0 : 1;
1246 }
1247
1248 if (bigintBitLen < numBitLen) {
1249 return bigintSign ? 1 : 0;
1250 }
1251 return -1;
1252 }
1253
CompareWithNumber(JSThread * thread,JSHandle<BigInt> bigint,JSHandle<JSTaggedValue> number)1254 ComparisonResult BigInt::CompareWithNumber(JSThread *thread, JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number)
1255 {
1256 double num = number->GetNumber();
1257 bool numberSign = num < 0;
1258 if (std::isnan(num)) {
1259 return ComparisonResult::UNDEFINED;
1260 }
1261 if (!std::isfinite(num)) {
1262 return (!numberSign ? ComparisonResult::LESS : ComparisonResult::GREAT);
1263 }
1264 // Bit operations must be of integer type
1265 uint64_t bits = 0;
1266 if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) {
1267 LOG_ECMA(FATAL) << "memset_s failed";
1268 UNREACHABLE();
1269 }
1270 int exponential = (bits >> 52) & 0x7FF;
1271
1272 // Take out bits 62-52 (11 bits in total) and subtract 1023
1273 int integerDigits = exponential - 0x3FF;
1274 uint64_t mantissa = (bits & 0x000FFFFFFFFFFFFF) | 0x0010000000000000;
1275 bool bigintSign = bigint->GetSign();
1276 // Handling the opposite sign
1277 if (!numberSign && bigintSign) {
1278 return ComparisonResult::LESS;
1279 } else if (numberSign && !bigintSign) {
1280 return ComparisonResult::GREAT;
1281 }
1282 if (bigint->IsZero() && !num) {
1283 return ComparisonResult::EQUAL;
1284 }
1285 if (bigint->IsZero() && num > 0) {
1286 return ComparisonResult::LESS;
1287 }
1288
1289 if (integerDigits < 0) {
1290 return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
1291 }
1292
1293 // Compare the significant bits of bigint with the significant integer bits of double
1294 int preZero = 0;
1295 int res = CompareToBitsLen(bigint, integerDigits + 1, preZero);
1296 if (res == 0) {
1297 return ComparisonResult::LESS;
1298 } else if (res == 1) {
1299 return ComparisonResult::GREAT;
1300 }
1301 int mantissaSize = 52; // mantissaSize
1302 uint32_t bigintLen = bigint->GetLength();
1303 int leftover = 0;
1304 bool IsFirstInto = true;
1305 for (int index = bigintLen - 1; index >= 0; --index) {
1306 uint32_t doubleNum = 0;
1307 uint32_t BigintNum = bigint->GetDigit(index);
1308 if (IsFirstInto) {
1309 IsFirstInto = false;
1310 leftover = mantissaSize - BigInt::DATEBITS + preZero + 1;
1311 doubleNum = static_cast<uint32_t>(mantissa >> leftover);
1312 mantissa = mantissa << (64 - leftover); // 64 double bits
1313 if (BigintNum > doubleNum) {
1314 return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
1315 }
1316 if (BigintNum < doubleNum) {
1317 return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
1318 }
1319 } else {
1320 leftover -= BigInt::DATEBITS;
1321 doubleNum = static_cast<uint32_t>(mantissa >> BigInt::DATEBITS);
1322 mantissa = mantissa << BigInt::DATEBITS;
1323 if (BigintNum > doubleNum) {
1324 return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
1325 }
1326 if (BigintNum < doubleNum) {
1327 return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
1328 }
1329 leftover -= BigInt::DATEBITS;
1330 }
1331 }
1332
1333 if (mantissa != 0) {
1334 ASSERT(leftover > 0);
1335 return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
1336 }
1337 return ComparisonResult::EQUAL;
1338 }
1339 } // namespace