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 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 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 JSHandle<BigInt> Int32ToBigInt(JSThread *thread, const int &number); 106 static JSHandle<BigInt> Uint32ToBigInt(JSThread *thread, const uint32_t &number); 107 static JSHandle<BigInt> Int64ToBigInt(JSThread *thread, const int64_t &number); 108 static JSHandle<BigInt> Uint64ToBigInt(JSThread *thread, const uint64_t &number); 109 int64_t ToInt64(); 110 uint64_t ToUint64(); 111 static void BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless); 112 static void BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless); 113 static JSHandle<BigInt> CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t* words); 114 static JSHandle<BigInt> FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal); 115 static JSTaggedValue AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint); 116 static JSTaggedValue AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint); 117 static JSTaggedNumber BigIntToNumber(JSHandle<BigInt> bigint); 118 static ComparisonResult CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number); 119 static JSHandle<BigInt> GetUint64MaxBigint(JSThread *thread); 120 static JSHandle<BigInt> GetInt64MaxBigint(JSThread *thread); ComputeSize(uint32_t length)121 static inline size_t ComputeSize(uint32_t length) 122 { 123 return DATA_OFFSET + sizeof(uint32_t) * length; 124 } 125 GetData()126 inline uint32_t *GetData() const 127 { 128 return reinterpret_cast<uint32_t *>(ToUintPtr(this) + DATA_OFFSET); 129 } 130 InitializationZero()131 inline void InitializationZero() 132 { 133 uint32_t size = GetLength() * sizeof(uint32_t); 134 if (memset_s(GetData(), size, 0, size) != EOK) { 135 LOG_FULL(FATAL) << "memset_s failed"; 136 UNREACHABLE(); 137 } 138 } 139 IsZero()140 inline bool IsZero() 141 { 142 return GetLength() == 1 && !GetDigit(0); 143 } 144 GetDigit(uint32_t index)145 inline uint32_t GetDigit(uint32_t index) const 146 { 147 ASSERT(index < GetLength()); 148 return Barriers::GetValue<uint32_t>(GetData(), sizeof(uint32_t) * index); 149 } 150 SetDigit(uint32_t index,uint32_t digit)151 inline void SetDigit(uint32_t index, uint32_t digit) 152 { 153 ASSERT(index < GetLength()); 154 Barriers::SetPrimitive<uint32_t>(GetData(), sizeof(uint32_t) * index, digit); 155 } 156 157 static constexpr size_t LENGTH_OFFSET = TaggedObjectSize(); 158 ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, BIT_FIELD_OFFSET) 159 ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) 160 DEFINE_ALIGN_SIZE(LAST_OFFSET); 161 static constexpr size_t DATA_OFFSET = SIZE; 162 163 // define BitField 164 static constexpr size_t SIGN_BITS = 1; 165 FIRST_BIT_FIELD(BitField, Sign, bool, SIGN_BITS) 166 167 DECL_DUMP() 168 169 private: 170 static bool Equal(const BigInt *x, const BigInt *y); 171 static bool LessThan(const BigInt *x, const BigInt *y); 172 static ComparisonResult Compare(const BigInt *x, const BigInt *y); 173 static ComparisonResult AbsolutelyCompare(const BigInt *x, const BigInt *y); IsUint32()174 inline uint32_t IsUint32() const 175 { 176 return GetLength() == 1; 177 } 178 }; 179 180 class BigIntHelper { 181 public: 182 static CString Conversion(const CString &num, uint32_t conversionToRadix, uint32_t currentRadix); 183 static JSHandle<BigInt> SetBigInt(JSThread *thread, const CString &numStr, 184 uint32_t currentRadix = BigInt::DECIMAL); 185 static CString GetBinary(const BigInt *bigint); 186 static JSHandle<BigInt> RightTruncate(JSThread *thread, JSHandle<BigInt> x); 187 188 static void DeZero(CString &a); 189 190 static uint32_t AddHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry); 191 static uint32_t SubHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry); 192 }; 193 static_assert((BigInt::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0); 194 } // namespace panda::ecmascript 195 #endif // ECMASCRIPT_TAGGED_BIGINT_H