• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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