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