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