1 // Copyright 2017 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_OBJECTS_BIGINT_H_ 6 #define V8_OBJECTS_BIGINT_H_ 7 8 #include "src/globals.h" 9 #include "src/objects.h" 10 #include "src/utils.h" 11 12 // Has to be the last include (doesn't have include guards): 13 #include "src/objects/object-macros.h" 14 15 namespace v8 { 16 namespace internal { 17 18 class BigInt; 19 class ValueDeserializer; 20 class ValueSerializer; 21 22 // BigIntBase is just the raw data object underlying a BigInt. Use with care! 23 // Most code should be using BigInts instead. 24 class BigIntBase : public HeapObject { 25 public: length()26 inline int length() const { 27 intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset); 28 return LengthBits::decode(static_cast<uint32_t>(bitfield)); 29 } 30 31 // Increasing kMaxLength will require code changes. 32 static const int kMaxLengthBits = kMaxInt - kPointerSize * kBitsPerByte - 1; 33 static const int kMaxLength = kMaxLengthBits / (kPointerSize * kBitsPerByte); 34 35 static const int kLengthFieldBits = 30; 36 STATIC_ASSERT(kMaxLength <= ((1 << kLengthFieldBits) - 1)); 37 class SignBits : public BitField<bool, 0, 1> {}; 38 class LengthBits : public BitField<int, SignBits::kNext, kLengthFieldBits> {}; 39 STATIC_ASSERT(LengthBits::kNext <= 32); 40 41 static const int kBitfieldOffset = HeapObject::kHeaderSize; 42 static const int kDigitsOffset = kBitfieldOffset + kPointerSize; 43 static const int kHeaderSize = kDigitsOffset; 44 45 private: 46 friend class ::v8::internal::BigInt; // MSVC wants full namespace. 47 friend class MutableBigInt; 48 49 typedef uintptr_t digit_t; 50 static const int kDigitSize = sizeof(digit_t); 51 // kMaxLength definition assumes this: 52 STATIC_ASSERT(kDigitSize == kPointerSize); 53 54 static const int kDigitBits = kDigitSize * kBitsPerByte; 55 static const int kHalfDigitBits = kDigitBits / 2; 56 static const digit_t kHalfDigitMask = (1ull << kHalfDigitBits) - 1; 57 58 // sign() == true means negative. sign()59 inline bool sign() const { 60 intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset); 61 return SignBits::decode(static_cast<uint32_t>(bitfield)); 62 } 63 digit(int n)64 inline digit_t digit(int n) const { 65 SLOW_DCHECK(0 <= n && n < length()); 66 Address address = FIELD_ADDR(this, kDigitsOffset + n * kDigitSize); 67 return *reinterpret_cast<digit_t*>(address); 68 } 69 is_zero()70 bool is_zero() const { return length() == 0; } 71 72 DISALLOW_IMPLICIT_CONSTRUCTORS(BigIntBase); 73 }; 74 75 class FreshlyAllocatedBigInt : public BigIntBase { 76 // This class is essentially the publicly accessible abstract version of 77 // MutableBigInt (which is a hidden implementation detail). It serves as 78 // the return type of Factory::NewBigInt, and makes it possible to enforce 79 // casting restrictions: 80 // - FreshlyAllocatedBigInt can be cast explicitly to MutableBigInt 81 // (with MutableBigInt::Cast) for initialization. 82 // - MutableBigInt can be cast/converted explicitly to BigInt 83 // (with MutableBigInt::MakeImmutable); is afterwards treated as readonly. 84 // - No accidental implicit casting is possible from BigInt to MutableBigInt 85 // (and no explicit operator is provided either). 86 87 public: 88 inline static FreshlyAllocatedBigInt* cast(Object* object); 89 90 private: 91 DISALLOW_IMPLICIT_CONSTRUCTORS(FreshlyAllocatedBigInt); 92 }; 93 94 // UNDER CONSTRUCTION! 95 // Arbitrary precision integers in JavaScript. 96 class V8_EXPORT_PRIVATE BigInt : public BigIntBase { 97 public: 98 // Implementation of the Spec methods, see: 99 // https://tc39.github.io/proposal-bigint/#sec-numeric-types 100 // Sections 1.1.1 through 1.1.19. 101 static Handle<BigInt> UnaryMinus(Isolate* isolate, Handle<BigInt> x); 102 static MaybeHandle<BigInt> BitwiseNot(Isolate* isolate, Handle<BigInt> x); 103 static MaybeHandle<BigInt> Exponentiate(Isolate* isolate, Handle<BigInt> base, 104 Handle<BigInt> exponent); 105 static MaybeHandle<BigInt> Multiply(Isolate* isolate, Handle<BigInt> x, 106 Handle<BigInt> y); 107 static MaybeHandle<BigInt> Divide(Isolate* isolate, Handle<BigInt> x, 108 Handle<BigInt> y); 109 static MaybeHandle<BigInt> Remainder(Isolate* isolate, Handle<BigInt> x, 110 Handle<BigInt> y); 111 static MaybeHandle<BigInt> Add(Isolate* isolate, Handle<BigInt> x, 112 Handle<BigInt> y); 113 static MaybeHandle<BigInt> Subtract(Isolate* isolate, Handle<BigInt> x, 114 Handle<BigInt> y); 115 static MaybeHandle<BigInt> LeftShift(Isolate* isolate, Handle<BigInt> x, 116 Handle<BigInt> y); 117 static MaybeHandle<BigInt> SignedRightShift(Isolate* isolate, 118 Handle<BigInt> x, 119 Handle<BigInt> y); 120 static MaybeHandle<BigInt> UnsignedRightShift(Isolate* isolate, 121 Handle<BigInt> x, 122 Handle<BigInt> y); 123 // More convenient version of "bool LessThan(x, y)". 124 static ComparisonResult CompareToBigInt(Handle<BigInt> x, Handle<BigInt> y); 125 static bool EqualToBigInt(BigInt* x, BigInt* y); 126 static MaybeHandle<BigInt> BitwiseAnd(Isolate* isolate, Handle<BigInt> x, 127 Handle<BigInt> y); 128 static MaybeHandle<BigInt> BitwiseXor(Isolate* isolate, Handle<BigInt> x, 129 Handle<BigInt> y); 130 static MaybeHandle<BigInt> BitwiseOr(Isolate* isolate, Handle<BigInt> x, 131 Handle<BigInt> y); 132 133 // Other parts of the public interface. 134 static MaybeHandle<BigInt> Increment(Isolate* isolate, Handle<BigInt> x); 135 static MaybeHandle<BigInt> Decrement(Isolate* isolate, Handle<BigInt> x); 136 ToBoolean()137 bool ToBoolean() { return !is_zero(); } Hash()138 uint32_t Hash() { 139 // TODO(jkummerow): Improve this. At least use length and sign. 140 return is_zero() ? 0 : ComputeIntegerHash(static_cast<uint32_t>(digit(0))); 141 } 142 143 static bool EqualToString(Isolate* isolate, Handle<BigInt> x, 144 Handle<String> y); 145 static bool EqualToNumber(Handle<BigInt> x, Handle<Object> y); 146 static ComparisonResult CompareToString(Isolate* isolate, Handle<BigInt> x, 147 Handle<String> y); 148 static ComparisonResult CompareToNumber(Handle<BigInt> x, Handle<Object> y); 149 // Exposed for tests, do not call directly. Use CompareToNumber() instead. 150 static ComparisonResult CompareToDouble(Handle<BigInt> x, double y); 151 152 static Handle<BigInt> AsIntN(Isolate* isolate, uint64_t n, Handle<BigInt> x); 153 static MaybeHandle<BigInt> AsUintN(Isolate* isolate, uint64_t n, 154 Handle<BigInt> x); 155 156 static Handle<BigInt> FromInt64(Isolate* isolate, int64_t n); 157 static Handle<BigInt> FromUint64(Isolate* isolate, uint64_t n); 158 static MaybeHandle<BigInt> FromWords64(Isolate* isolate, int sign_bit, 159 int words64_count, 160 const uint64_t* words); 161 int64_t AsInt64(bool* lossless = nullptr); 162 uint64_t AsUint64(bool* lossless = nullptr); 163 int Words64Count(); 164 void ToWordsArray64(int* sign_bit, int* words64_count, uint64_t* words); 165 166 DECL_CAST(BigInt) 167 DECL_VERIFIER(BigInt) 168 DECL_PRINTER(BigInt) 169 void BigIntShortPrint(std::ostream& os); 170 SizeFor(int length)171 inline static int SizeFor(int length) { 172 return kHeaderSize + length * kDigitSize; 173 } 174 175 static MaybeHandle<String> ToString(Isolate* isolate, Handle<BigInt> bigint, 176 int radix = 10); 177 // "The Number value for x", see: 178 // https://tc39.github.io/ecma262/#sec-ecmascript-language-types-number-type 179 // Returns a Smi or HeapNumber. 180 static Handle<Object> ToNumber(Isolate* isolate, Handle<BigInt> x); 181 182 // ECMAScript's NumberToBigInt 183 static MaybeHandle<BigInt> FromNumber(Isolate* isolate, 184 Handle<Object> number); 185 186 // ECMAScript's ToBigInt (throws for Number input) 187 static MaybeHandle<BigInt> FromObject(Isolate* isolate, Handle<Object> obj); 188 189 class BodyDescriptor; 190 191 private: 192 friend class StringToBigIntHelper; 193 friend class ValueDeserializer; 194 friend class ValueSerializer; 195 196 // Special functions for StringToBigIntHelper: 197 static Handle<BigInt> Zero(Isolate* isolate); 198 static MaybeHandle<FreshlyAllocatedBigInt> AllocateFor( 199 Isolate* isolate, int radix, int charcount, ShouldThrow should_throw, 200 PretenureFlag pretenure); 201 static void InplaceMultiplyAdd(Handle<FreshlyAllocatedBigInt> x, 202 uintptr_t factor, uintptr_t summand); 203 static Handle<BigInt> Finalize(Handle<FreshlyAllocatedBigInt> x, bool sign); 204 205 // Special functions for ValueSerializer/ValueDeserializer: 206 uint32_t GetBitfieldForSerialization() const; 207 static int DigitsByteLengthForBitfield(uint32_t bitfield); 208 // Expects {storage} to have a length of at least 209 // {DigitsByteLengthForBitfield(GetBitfieldForSerialization())}. 210 void SerializeDigits(uint8_t* storage); 211 V8_WARN_UNUSED_RESULT static MaybeHandle<BigInt> FromSerializedDigits( 212 Isolate* isolate, uint32_t bitfield, Vector<const uint8_t> digits_storage, 213 PretenureFlag pretenure); 214 215 DISALLOW_IMPLICIT_CONSTRUCTORS(BigInt); 216 }; 217 218 } // namespace internal 219 } // namespace v8 220 221 #include "src/objects/object-macros-undef.h" 222 223 #endif // V8_OBJECTS_BIGINT_H_ 224