Home | History | Annotate | Download | only in objects
      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:
     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.
     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 
     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 
     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 
    137   bool ToBoolean() { return !is_zero(); }
    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 
    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