1 /* 2 * Copyright (c) 2022-2024 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 #ifndef ECMASCRIPT_JS_BIGINT_H 17 #define ECMASCRIPT_JS_BIGINT_H 18 19 #include "ecmascript/ecma_macros.h" 20 #include "ecmascript/js_handle.h" 21 #include "ecmascript/js_object.h" 22 #include "ecmascript/mem/mem_common.h" 23 #include "ecmascript/mem/space.h" 24 25 #include "securec.h" 26 27 namespace panda::ecmascript { 28 enum class Operate : uint32_t { AND = 0, OR, XOR }; 29 enum class ComparisonResult; 30 class JSThread; 31 32 class BigInt : public TaggedObject { 33 public: 34 static constexpr uint32_t DATA_BITS = sizeof(uint32_t) * 8; // 8 : one-bit number of bytes 35 static constexpr uint32_t MAXBITS = 1_MB; // 1 MB : Maximum space that can be opened up 36 static constexpr uint32_t kMaxLengthBits = 1 << 30; // ~1 billion. 37 static constexpr uint32_t MAXSIZE = MAXBITS / DATA_BITS; // the maximum value of size 38 static constexpr uint32_t MAXOCTALVALUE = 7; // 7 : max octal value 39 static constexpr uint32_t BINARY = 2; // 2 : binary 40 41 static constexpr uint32_t OCTAL = 8; // 8 : octal 42 static constexpr uint32_t DECIMAL = 10; // 10 : decimal 43 static constexpr uint32_t HEXADECIMAL = 16; // 16 : hexadecimal 44 static constexpr uint32_t HALF_DATA_BITS = DATA_BITS / 2; 45 static constexpr uint32_t HALF_UINT32_VALUE = 1U << HALF_DATA_BITS; 46 static constexpr uint32_t HALF_DATA_MASK = HALF_UINT32_VALUE - 1; 47 CAST_CHECK(BigInt, IsBigInt); 48 template <MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE> 49 static JSHandle<BigInt> CreateBigint(JSThread *thread, uint32_t size); 50 51 template <MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE> 52 static JSHandle<BigInt> CreateRawBigInt(JSThread *thread, uint32_t size); 53 54 template <MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE> 55 static JSHandle<BigInt> CreateSubBigInt(JSThread *thread, const JSHandle<BigInt>& x, uint32_t size); 56 57 static bool Equal(const JSTaggedValue &x, const JSTaggedValue &y); 58 static PUBLIC_API bool SameValue(const JSTaggedValue &x, const JSTaggedValue &y); 59 static bool SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y); 60 61 static JSHandle<BigInt> BitwiseOp(JSThread *thread, Operate op, JSHandle<BigInt> x, JSHandle<BigInt> y); 62 static JSHandle<BigInt> BitwiseAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 63 static JSHandle<BigInt> BitwiseXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 64 static JSHandle<BigInt> BitwiseOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 65 static JSHandle<BigInt> BitwiseSubOne(JSThread *thread, JSHandle<BigInt> bigint, uint32_t maxLen); 66 static JSHandle<BigInt> BitwiseAddOne(JSThread *thread, JSHandle<BigInt> bigint); 67 static JSHandle<EcmaString> ToString(JSThread *thread, JSHandle<BigInt> bigint, 68 uint32_t conversionToRadix = BigInt::DECIMAL); 69 template <typename DstType> 70 static void AppendToCString(DstType &str, BigInt *bigint, uint32_t conversionToRadix = BigInt::DECIMAL); 71 72 CString ToStdString(uint32_t conversionToRadix) const; 73 74 static JSHandle<BigInt> UnaryMinus(JSThread *thread, JSHandle<BigInt> x); 75 static JSHandle<BigInt> BitwiseNOT(JSThread *thread, JSHandle<BigInt> x); 76 static JSHandle<BigInt> Exponentiate(JSThread *thread, JSHandle<BigInt> base, JSHandle<BigInt> exponent); 77 static std::tuple<uint32_t, uint32_t> Mul(uint32_t x, uint32_t y); 78 static JSHandle<BigInt> Multiply(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 79 static uint32_t DivideAndRemainder(uint32_t highBit, uint32_t lowBit, uint32_t divisor, uint32_t& remainder); 80 static JSHandle<BigInt> FormatLeftShift(JSThread *thread, uint32_t shift, JSHandle<BigInt> bigint, 81 bool neeedAddOne); 82 static void UnformattedRightShift(JSHandle<BigInt> bigint, uint32_t shift); 83 static bool SpecialMultiplyAndSub(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t q, JSHandle<BigInt> qv, 84 uint32_t pos); 85 static uint32_t SpecialAdd(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t pos); 86 static uint32_t ImproveAccuracy(uint32_t vHighest, uint32_t vHighestNext, uint32_t UHighest, 87 uint32_t UHighestNext, uint32_t q); 88 static JSHandle<BigInt> DivideAndRemainderWithBigintDivisor(JSThread *thread, JSHandle<BigInt> dividend, 89 JSHandle<BigInt> divisor, 90 JSMutableHandle<BigInt> &remainder); 91 static JSHandle<BigInt> DivideAndRemainderWithUint32Divisor(JSThread *thread, JSHandle<BigInt> dividend, 92 uint32_t divisor, JSMutableHandle<BigInt> &remainder); 93 static JSHandle<BigInt> Divide(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 94 static JSHandle<BigInt> Remainder(JSThread *thread, JSHandle<BigInt> n, JSHandle<BigInt> d); 95 static JSHandle<BigInt> BigintAddOne(JSThread *thread, JSHandle<BigInt> x); 96 static JSHandle<BigInt> BigintSubOne(JSThread *thread, JSHandle<BigInt> x); 97 static JSHandle<BigInt> Copy(JSThread *thread, JSHandle<BigInt> x, uint32_t len); 98 99 static JSHandle<BigInt> Add(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 100 static JSHandle<BigInt> Subtract(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 101 static bool LessThan(const JSTaggedValue &x, const JSTaggedValue &y); 102 static ComparisonResult Compare(const JSTaggedValue &x, const JSTaggedValue &y); 103 static JSHandle<BigInt> SignedRightShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 104 static JSHandle<BigInt> ReturnIfRightShiftOverMax(JSThread *thread, bool sign); 105 static void RightShift(JSHandle<BigInt> bigint, JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove); 106 static void JudgeRoundDown(JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove, uint32_t &needLen, 107 bool &roundDown); 108 static JSHandle<BigInt> RightShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 109 static JSTaggedValue UnsignedRightShift(JSThread *thread); 110 static JSHandle<BigInt> LeftShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 111 static JSHandle<BigInt> LeftShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y); 112 static JSHandle<BigInt> BigintAdd(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign); 113 static JSHandle<BigInt> BigintSub(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign); 114 115 static JSTaggedValue NumberToBigInt(JSThread *thread, JSHandle<JSTaggedValue> number); 116 static JSTaggedValue PUBLIC_API DoubleToBigInt(JSThread *thread, double value); 117 static JSHandle<BigInt> PUBLIC_API Int32ToBigInt(JSThread *thread, const int &number); 118 static JSHandle<BigInt> Uint32ToBigInt(JSThread *thread, const uint32_t &number); 119 static JSHandle<BigInt> Int64ToBigInt(JSThread *thread, const int64_t &number); 120 static JSHandle<BigInt> Uint64ToBigInt(JSThread *thread, const uint64_t &number); 121 int64_t ToInt64(); 122 uint64_t ToUint64(); 123 static void BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless); 124 static void BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless); 125 static JSHandle<BigInt> CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t* words); 126 static JSHandle<BigInt> FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal); 127 static JSTaggedValue AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint); 128 static JSTaggedValue AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint); 129 static JSTaggedNumber BigIntToNumber(JSHandle<BigInt> bigint); 130 static ComparisonResult CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number); 131 static JSHandle<BigInt> CreateUint64MaxBigInt(JSThread *thread); 132 static JSHandle<BigInt> CreateInt64MaxBigInt(JSThread *thread); 133 static JSHandle<BigInt> GetUint64MaxBigInt(JSThread *thread); 134 static JSHandle<BigInt> GetInt64MaxBigInt(JSThread *thread); ComputeSize(uint32_t length)135 static inline size_t ComputeSize(uint32_t length) 136 { 137 return DATA_OFFSET + sizeof(uint32_t) * length; 138 } 139 GetData()140 inline uint32_t *GetData() const 141 { 142 return reinterpret_cast<uint32_t *>(ToUintPtr(this) + DATA_OFFSET); 143 } 144 InitializationZero()145 inline void InitializationZero() 146 { 147 uint32_t size = GetLength() * sizeof(uint32_t); 148 if (memset_s(GetData(), size, 0, size) != EOK) { 149 LOG_FULL(FATAL) << "memset_s failed"; 150 UNREACHABLE(); 151 } 152 } 153 IsZero()154 inline bool IsZero() 155 { 156 return GetLength() == 1 && !GetDigit(0); 157 } 158 GetDigit(uint32_t index)159 inline uint32_t GetDigit(uint32_t index) const 160 { 161 ASSERT(index < GetLength()); 162 return Barriers::GetPrimitive<uint32_t>(GetData(), sizeof(uint32_t) * index); 163 } 164 SetDigit(uint32_t index,uint32_t digit)165 inline void SetDigit(uint32_t index, uint32_t digit) 166 { 167 ASSERT(index < GetLength()); 168 Barriers::SetPrimitive<uint32_t>(GetData(), sizeof(uint32_t) * index, digit); 169 } 170 171 static constexpr size_t LENGTH_OFFSET = TaggedObjectSize(); 172 ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, BIT_FIELD_OFFSET) 173 ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) 174 DEFINE_ALIGN_SIZE(LAST_OFFSET); 175 176 static constexpr size_t DATA_OFFSET = SIZE; 177 178 DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetPointerLength()); 179 180 // define BitField 181 static constexpr size_t SIGN_BITS = 1; 182 FIRST_BIT_FIELD(BitField, Sign, bool, SIGN_BITS) 183 184 DECL_DUMP() 185 186 private: 187 static bool Equal(const BigInt *x, const BigInt *y); 188 static bool LessThan(const BigInt *x, const BigInt *y); 189 static ComparisonResult Compare(const BigInt *x, const BigInt *y); 190 static ComparisonResult AbsolutelyCompare(const BigInt *x, const BigInt *y); IsUint32()191 inline uint32_t IsUint32() const 192 { 193 return GetLength() == 1; 194 } 195 GetPointerLength()196 inline size_t GetPointerLength() 197 { 198 size_t byteSize = DataSize(this); 199 return AlignUp(byteSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) / sizeof(JSTaggedType); 200 } 201 DataSize(BigInt * bigInt)202 static inline size_t DataSize(BigInt *bigInt) 203 { 204 uint32_t length = bigInt->GetLength(); 205 return length * sizeof(uint32_t); 206 } 207 }; 208 209 class BigIntHelper { 210 public: 211 static CString Conversion(const CString &num, uint32_t conversionToRadix, uint32_t currentRadix); 212 static JSHandle<BigInt> SetBigInt(JSThread *thread, const CString &numStr, 213 uint32_t currentRadix = BigInt::DECIMAL); 214 static CString GetBinary(const BigInt *bigint); 215 static JSHandle<BigInt> RightTruncate(JSThread *thread, JSHandle<BigInt> x); 216 217 static void DeZero(CString &a); 218 219 static uint32_t AddHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry); 220 static uint32_t SubHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry); 221 }; 222 static_assert((BigInt::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0); 223 } // namespace panda::ecmascript 224 #endif // ECMASCRIPT_TAGGED_BIGINT_H 225