14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_JS_BIGINT_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_JS_BIGINT_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/ecma_macros.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_handle.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_object.h" 224514f5e3Sopenharmony_ci#include "ecmascript/mem/mem_common.h" 234514f5e3Sopenharmony_ci 244514f5e3Sopenharmony_ci#include "securec.h" 254514f5e3Sopenharmony_ci 264514f5e3Sopenharmony_cinamespace panda::ecmascript { 274514f5e3Sopenharmony_cienum class Operate : uint32_t { AND = 0, OR, XOR }; 284514f5e3Sopenharmony_cienum class ComparisonResult; 294514f5e3Sopenharmony_ciclass JSThread; 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ciclass BigInt : public TaggedObject { 324514f5e3Sopenharmony_cipublic: 334514f5e3Sopenharmony_ci static constexpr uint32_t DATEBITS = sizeof(uint32_t) * 8; // 8 : one-bit number of bytes 344514f5e3Sopenharmony_ci static constexpr uint32_t MAXBITS = 1_MB; // 1 MB : Maximum space that can be opened up 354514f5e3Sopenharmony_ci static constexpr uint32_t kMaxLengthBits = 1 << 30; // ~1 billion. 364514f5e3Sopenharmony_ci static constexpr uint32_t MAXSIZE = MAXBITS / DATEBITS; // the maximum value of size 374514f5e3Sopenharmony_ci static constexpr uint32_t MAXOCTALVALUE = 7; // 7 : max octal value 384514f5e3Sopenharmony_ci static constexpr uint32_t BINARY = 2; // 2 : binary 394514f5e3Sopenharmony_ci 404514f5e3Sopenharmony_ci static constexpr uint32_t OCTAL = 8; // 8 : octal 414514f5e3Sopenharmony_ci static constexpr uint32_t DECIMAL = 10; // 10 : decimal 424514f5e3Sopenharmony_ci static constexpr uint32_t HEXADECIMAL = 16; // 16 : hexadecimal 434514f5e3Sopenharmony_ci static constexpr uint32_t HALFDATEBITS = DATEBITS / 2; 444514f5e3Sopenharmony_ci static constexpr uint32_t HALFUINT32VALUE = 1U << HALFDATEBITS; 454514f5e3Sopenharmony_ci static constexpr uint32_t HALFDATEMASK = HALFUINT32VALUE - 1; 464514f5e3Sopenharmony_ci CAST_CHECK(BigInt, IsBigInt); 474514f5e3Sopenharmony_ci static JSHandle<BigInt> CreateBigint(JSThread *thread, uint32_t size); 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ci static bool Equal(const JSTaggedValue &x, const JSTaggedValue &y); 504514f5e3Sopenharmony_ci static PUBLIC_API bool SameValue(const JSTaggedValue &x, const JSTaggedValue &y); 514514f5e3Sopenharmony_ci static bool SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y); 524514f5e3Sopenharmony_ci 534514f5e3Sopenharmony_ci static JSHandle<BigInt> BitwiseOp(JSThread *thread, Operate op, JSHandle<BigInt> x, JSHandle<BigInt> y); 544514f5e3Sopenharmony_ci static JSHandle<BigInt> BitwiseAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 554514f5e3Sopenharmony_ci static JSHandle<BigInt> BitwiseXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 564514f5e3Sopenharmony_ci static JSHandle<BigInt> BitwiseOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 574514f5e3Sopenharmony_ci static JSHandle<BigInt> BitwiseSubOne(JSThread *thread, JSHandle<BigInt> bigint, uint32_t maxLen); 584514f5e3Sopenharmony_ci static JSHandle<BigInt> BitwiseAddOne(JSThread *thread, JSHandle<BigInt> bigint); 594514f5e3Sopenharmony_ci static JSHandle<EcmaString> ToString(JSThread *thread, JSHandle<BigInt> bigint, 604514f5e3Sopenharmony_ci uint32_t conversionToRadix = BigInt::DECIMAL); 614514f5e3Sopenharmony_ci CString ToStdString(uint32_t conversionToRadix) const; 624514f5e3Sopenharmony_ci 634514f5e3Sopenharmony_ci static JSHandle<BigInt> UnaryMinus(JSThread *thread, JSHandle<BigInt> x); 644514f5e3Sopenharmony_ci static JSHandle<BigInt> BitwiseNOT(JSThread *thread, JSHandle<BigInt> x); 654514f5e3Sopenharmony_ci static JSHandle<BigInt> Exponentiate(JSThread *thread, JSHandle<BigInt> base, JSHandle<BigInt> exponent); 664514f5e3Sopenharmony_ci static std::tuple<uint32_t, uint32_t> Mul(uint32_t x, uint32_t y); 674514f5e3Sopenharmony_ci static JSHandle<BigInt> Multiply(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 684514f5e3Sopenharmony_ci static uint32_t DivideAndRemainder(uint32_t highBit, uint32_t lowBit, uint32_t divisor, uint32_t& remainder); 694514f5e3Sopenharmony_ci static JSHandle<BigInt> FormatLeftShift(JSThread *thread, uint32_t shift, JSHandle<BigInt> bigint, 704514f5e3Sopenharmony_ci bool neeedAddOne); 714514f5e3Sopenharmony_ci static void UnformattedRightShift(JSHandle<BigInt> bigint, uint32_t shift); 724514f5e3Sopenharmony_ci static bool SpecialMultiplyAndSub(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t q, JSHandle<BigInt> qv, 734514f5e3Sopenharmony_ci uint32_t pos); 744514f5e3Sopenharmony_ci static uint32_t SpecialAdd(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t pos); 754514f5e3Sopenharmony_ci static uint32_t ImproveAccuracy(uint32_t vHighest, uint32_t vHighestNext, uint32_t UHighest, 764514f5e3Sopenharmony_ci uint32_t UHighestNext, uint32_t q); 774514f5e3Sopenharmony_ci static JSHandle<BigInt> DivideAndRemainderWithBigintDivisor(JSThread *thread, JSHandle<BigInt> dividend, 784514f5e3Sopenharmony_ci JSHandle<BigInt> divisor, 794514f5e3Sopenharmony_ci JSMutableHandle<BigInt> &remainder); 804514f5e3Sopenharmony_ci static JSHandle<BigInt> DivideAndRemainderWithUint32Divisor(JSThread *thread, JSHandle<BigInt> dividend, 814514f5e3Sopenharmony_ci uint32_t divisor, JSMutableHandle<BigInt> &remainder); 824514f5e3Sopenharmony_ci static JSHandle<BigInt> Divide(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 834514f5e3Sopenharmony_ci static JSHandle<BigInt> Remainder(JSThread *thread, JSHandle<BigInt> n, JSHandle<BigInt> d); 844514f5e3Sopenharmony_ci static JSHandle<BigInt> BigintAddOne(JSThread *thread, JSHandle<BigInt> x); 854514f5e3Sopenharmony_ci static JSHandle<BigInt> BigintSubOne(JSThread *thread, JSHandle<BigInt> x); 864514f5e3Sopenharmony_ci static JSHandle<BigInt> Copy(JSThread *thread, JSHandle<BigInt> x, uint32_t len); 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ci static JSHandle<BigInt> Add(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 894514f5e3Sopenharmony_ci static JSHandle<BigInt> Subtract(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 904514f5e3Sopenharmony_ci static bool LessThan(const JSTaggedValue &x, const JSTaggedValue &y); 914514f5e3Sopenharmony_ci static ComparisonResult Compare(const JSTaggedValue &x, const JSTaggedValue &y); 924514f5e3Sopenharmony_ci static JSHandle<BigInt> SignedRightShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 934514f5e3Sopenharmony_ci static JSHandle<BigInt> ReturnIfRightShiftOverMax(JSThread *thread, bool sign); 944514f5e3Sopenharmony_ci static void RightShift(JSHandle<BigInt> bigint, JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove); 954514f5e3Sopenharmony_ci static void JudgeRoundDown(JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove, uint32_t &needLen, 964514f5e3Sopenharmony_ci bool &roundDown); 974514f5e3Sopenharmony_ci static JSHandle<BigInt> RightShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 984514f5e3Sopenharmony_ci static JSTaggedValue UnsignedRightShift(JSThread *thread); 994514f5e3Sopenharmony_ci static JSHandle<BigInt> LeftShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 1004514f5e3Sopenharmony_ci static JSHandle<BigInt> LeftShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 1014514f5e3Sopenharmony_ci static JSHandle<BigInt> BigintAdd(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign); 1024514f5e3Sopenharmony_ci static JSHandle<BigInt> BigintSub(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign); 1034514f5e3Sopenharmony_ci 1044514f5e3Sopenharmony_ci static JSTaggedValue NumberToBigInt(JSThread *thread, JSHandle<JSTaggedValue> number); 1054514f5e3Sopenharmony_ci static JSTaggedValue PUBLIC_API DoubleToBigInt(JSThread *thread, double value); 1064514f5e3Sopenharmony_ci static JSHandle<BigInt> PUBLIC_API Int32ToBigInt(JSThread *thread, const int &number); 1074514f5e3Sopenharmony_ci static JSHandle<BigInt> Uint32ToBigInt(JSThread *thread, const uint32_t &number); 1084514f5e3Sopenharmony_ci static JSHandle<BigInt> Int64ToBigInt(JSThread *thread, const int64_t &number); 1094514f5e3Sopenharmony_ci static JSHandle<BigInt> Uint64ToBigInt(JSThread *thread, const uint64_t &number); 1104514f5e3Sopenharmony_ci int64_t ToInt64(); 1114514f5e3Sopenharmony_ci uint64_t ToUint64(); 1124514f5e3Sopenharmony_ci static void BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless); 1134514f5e3Sopenharmony_ci static void BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless); 1144514f5e3Sopenharmony_ci static JSHandle<BigInt> CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t* words); 1154514f5e3Sopenharmony_ci static JSHandle<BigInt> FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal); 1164514f5e3Sopenharmony_ci static JSTaggedValue AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint); 1174514f5e3Sopenharmony_ci static JSTaggedValue AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint); 1184514f5e3Sopenharmony_ci static JSTaggedNumber BigIntToNumber(JSHandle<BigInt> bigint); 1194514f5e3Sopenharmony_ci static ComparisonResult CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number); 1204514f5e3Sopenharmony_ci static JSHandle<BigInt> CreateUint64MaxBigInt(JSThread *thread); 1214514f5e3Sopenharmony_ci static JSHandle<BigInt> CreateInt64MaxBigInt(JSThread *thread); 1224514f5e3Sopenharmony_ci static JSHandle<BigInt> GetUint64MaxBigInt(JSThread *thread); 1234514f5e3Sopenharmony_ci static JSHandle<BigInt> GetInt64MaxBigInt(JSThread *thread); 1244514f5e3Sopenharmony_ci static inline size_t ComputeSize(uint32_t length) 1254514f5e3Sopenharmony_ci { 1264514f5e3Sopenharmony_ci return DATA_OFFSET + sizeof(uint32_t) * length; 1274514f5e3Sopenharmony_ci } 1284514f5e3Sopenharmony_ci 1294514f5e3Sopenharmony_ci inline uint32_t *GetData() const 1304514f5e3Sopenharmony_ci { 1314514f5e3Sopenharmony_ci return reinterpret_cast<uint32_t *>(ToUintPtr(this) + DATA_OFFSET); 1324514f5e3Sopenharmony_ci } 1334514f5e3Sopenharmony_ci 1344514f5e3Sopenharmony_ci inline void InitializationZero() 1354514f5e3Sopenharmony_ci { 1364514f5e3Sopenharmony_ci uint32_t size = GetLength() * sizeof(uint32_t); 1374514f5e3Sopenharmony_ci if (memset_s(GetData(), size, 0, size) != EOK) { 1384514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "memset_s failed"; 1394514f5e3Sopenharmony_ci UNREACHABLE(); 1404514f5e3Sopenharmony_ci } 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci 1434514f5e3Sopenharmony_ci inline bool IsZero() 1444514f5e3Sopenharmony_ci { 1454514f5e3Sopenharmony_ci return GetLength() == 1 && !GetDigit(0); 1464514f5e3Sopenharmony_ci } 1474514f5e3Sopenharmony_ci 1484514f5e3Sopenharmony_ci inline uint32_t GetDigit(uint32_t index) const 1494514f5e3Sopenharmony_ci { 1504514f5e3Sopenharmony_ci ASSERT(index < GetLength()); 1514514f5e3Sopenharmony_ci return Barriers::GetValue<uint32_t>(GetData(), sizeof(uint32_t) * index); 1524514f5e3Sopenharmony_ci } 1534514f5e3Sopenharmony_ci 1544514f5e3Sopenharmony_ci inline void SetDigit(uint32_t index, uint32_t digit) 1554514f5e3Sopenharmony_ci { 1564514f5e3Sopenharmony_ci ASSERT(index < GetLength()); 1574514f5e3Sopenharmony_ci Barriers::SetPrimitive<uint32_t>(GetData(), sizeof(uint32_t) * index, digit); 1584514f5e3Sopenharmony_ci } 1594514f5e3Sopenharmony_ci 1604514f5e3Sopenharmony_ci static constexpr size_t LENGTH_OFFSET = TaggedObjectSize(); 1614514f5e3Sopenharmony_ci ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, BIT_FIELD_OFFSET) 1624514f5e3Sopenharmony_ci ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) 1634514f5e3Sopenharmony_ci DEFINE_ALIGN_SIZE(LAST_OFFSET); 1644514f5e3Sopenharmony_ci 1654514f5e3Sopenharmony_ci static constexpr size_t DATA_OFFSET = SIZE; 1664514f5e3Sopenharmony_ci 1674514f5e3Sopenharmony_ci DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetPointerLength()); 1684514f5e3Sopenharmony_ci 1694514f5e3Sopenharmony_ci // define BitField 1704514f5e3Sopenharmony_ci static constexpr size_t SIGN_BITS = 1; 1714514f5e3Sopenharmony_ci FIRST_BIT_FIELD(BitField, Sign, bool, SIGN_BITS) 1724514f5e3Sopenharmony_ci 1734514f5e3Sopenharmony_ci DECL_DUMP() 1744514f5e3Sopenharmony_ci 1754514f5e3Sopenharmony_ciprivate: 1764514f5e3Sopenharmony_ci static bool Equal(const BigInt *x, const BigInt *y); 1774514f5e3Sopenharmony_ci static bool LessThan(const BigInt *x, const BigInt *y); 1784514f5e3Sopenharmony_ci static ComparisonResult Compare(const BigInt *x, const BigInt *y); 1794514f5e3Sopenharmony_ci static ComparisonResult AbsolutelyCompare(const BigInt *x, const BigInt *y); 1804514f5e3Sopenharmony_ci inline uint32_t IsUint32() const 1814514f5e3Sopenharmony_ci { 1824514f5e3Sopenharmony_ci return GetLength() == 1; 1834514f5e3Sopenharmony_ci } 1844514f5e3Sopenharmony_ci 1854514f5e3Sopenharmony_ci inline size_t GetPointerLength() 1864514f5e3Sopenharmony_ci { 1874514f5e3Sopenharmony_ci size_t byteSize = DataSize(this); 1884514f5e3Sopenharmony_ci return AlignUp(byteSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) / sizeof(JSTaggedType); 1894514f5e3Sopenharmony_ci } 1904514f5e3Sopenharmony_ci 1914514f5e3Sopenharmony_ci static inline size_t DataSize(BigInt *bigInt) 1924514f5e3Sopenharmony_ci { 1934514f5e3Sopenharmony_ci uint32_t length = bigInt->GetLength(); 1944514f5e3Sopenharmony_ci return length * sizeof(uint32_t); 1954514f5e3Sopenharmony_ci } 1964514f5e3Sopenharmony_ci}; 1974514f5e3Sopenharmony_ci 1984514f5e3Sopenharmony_ciclass BigIntHelper { 1994514f5e3Sopenharmony_cipublic: 2004514f5e3Sopenharmony_ci static CString Conversion(const CString &num, uint32_t conversionToRadix, uint32_t currentRadix); 2014514f5e3Sopenharmony_ci static JSHandle<BigInt> SetBigInt(JSThread *thread, const CString &numStr, 2024514f5e3Sopenharmony_ci uint32_t currentRadix = BigInt::DECIMAL); 2034514f5e3Sopenharmony_ci static CString GetBinary(const BigInt *bigint); 2044514f5e3Sopenharmony_ci static JSHandle<BigInt> RightTruncate(JSThread *thread, JSHandle<BigInt> x); 2054514f5e3Sopenharmony_ci 2064514f5e3Sopenharmony_ci static void DeZero(CString &a); 2074514f5e3Sopenharmony_ci 2084514f5e3Sopenharmony_ci static uint32_t AddHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry); 2094514f5e3Sopenharmony_ci static uint32_t SubHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry); 2104514f5e3Sopenharmony_ci}; 2114514f5e3Sopenharmony_cistatic_assert((BigInt::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0); 2124514f5e3Sopenharmony_ci} // namespace panda::ecmascript 2134514f5e3Sopenharmony_ci#endif // ECMASCRIPT_TAGGED_BIGINT_H