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