blob: f8c5c3dbf697981d6c4e36b94a7d1f1c7a7046b2 [file] [log] [blame]
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_BIGINT_H_
#define V8_OBJECTS_BIGINT_H_
#include "src/globals.h"
#include "src/objects.h"
#include "src/utils.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class BigInt;
class ValueDeserializer;
class ValueSerializer;
// BigIntBase is just the raw data object underlying a BigInt. Use with care!
// Most code should be using BigInts instead.
class BigIntBase : public HeapObject {
public:
inline int length() const {
intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset);
return LengthBits::decode(static_cast<uint32_t>(bitfield));
}
// Increasing kMaxLength will require code changes.
static const int kMaxLengthBits = kMaxInt - kPointerSize * kBitsPerByte - 1;
static const int kMaxLength = kMaxLengthBits / (kPointerSize * kBitsPerByte);
static const int kLengthFieldBits = 30;
STATIC_ASSERT(kMaxLength <= ((1 << kLengthFieldBits) - 1));
class SignBits : public BitField<bool, 0, 1> {};
class LengthBits : public BitField<int, SignBits::kNext, kLengthFieldBits> {};
STATIC_ASSERT(LengthBits::kNext <= 32);
static const int kBitfieldOffset = HeapObject::kHeaderSize;
static const int kDigitsOffset = kBitfieldOffset + kPointerSize;
static const int kHeaderSize = kDigitsOffset;
private:
friend class ::v8::internal::BigInt; // MSVC wants full namespace.
friend class MutableBigInt;
typedef uintptr_t digit_t;
static const int kDigitSize = sizeof(digit_t);
// kMaxLength definition assumes this:
STATIC_ASSERT(kDigitSize == kPointerSize);
static const int kDigitBits = kDigitSize * kBitsPerByte;
static const int kHalfDigitBits = kDigitBits / 2;
static const digit_t kHalfDigitMask = (1ull << kHalfDigitBits) - 1;
// sign() == true means negative.
inline bool sign() const {
intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset);
return SignBits::decode(static_cast<uint32_t>(bitfield));
}
inline digit_t digit(int n) const {
SLOW_DCHECK(0 <= n && n < length());
Address address = FIELD_ADDR(this, kDigitsOffset + n * kDigitSize);
return *reinterpret_cast<digit_t*>(address);
}
bool is_zero() const { return length() == 0; }
DISALLOW_IMPLICIT_CONSTRUCTORS(BigIntBase);
};
class FreshlyAllocatedBigInt : public BigIntBase {
// This class is essentially the publicly accessible abstract version of
// MutableBigInt (which is a hidden implementation detail). It serves as
// the return type of Factory::NewBigInt, and makes it possible to enforce
// casting restrictions:
// - FreshlyAllocatedBigInt can be cast explicitly to MutableBigInt
// (with MutableBigInt::Cast) for initialization.
// - MutableBigInt can be cast/converted explicitly to BigInt
// (with MutableBigInt::MakeImmutable); is afterwards treated as readonly.
// - No accidental implicit casting is possible from BigInt to MutableBigInt
// (and no explicit operator is provided either).
public:
inline static FreshlyAllocatedBigInt* cast(Object* object);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(FreshlyAllocatedBigInt);
};
// UNDER CONSTRUCTION!
// Arbitrary precision integers in JavaScript.
class V8_EXPORT_PRIVATE BigInt : public BigIntBase {
public:
// Implementation of the Spec methods, see:
// https://tc39.github.io/proposal-bigint/#sec-numeric-types
// Sections 1.1.1 through 1.1.19.
static Handle<BigInt> UnaryMinus(Isolate* isolate, Handle<BigInt> x);
static MaybeHandle<BigInt> BitwiseNot(Isolate* isolate, Handle<BigInt> x);
static MaybeHandle<BigInt> Exponentiate(Isolate* isolate, Handle<BigInt> base,
Handle<BigInt> exponent);
static MaybeHandle<BigInt> Multiply(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> Divide(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> Remainder(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> Add(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> Subtract(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> LeftShift(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> SignedRightShift(Isolate* isolate,
Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> UnsignedRightShift(Isolate* isolate,
Handle<BigInt> x,
Handle<BigInt> y);
// More convenient version of "bool LessThan(x, y)".
static ComparisonResult CompareToBigInt(Handle<BigInt> x, Handle<BigInt> y);
static bool EqualToBigInt(BigInt* x, BigInt* y);
static MaybeHandle<BigInt> BitwiseAnd(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> BitwiseXor(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
static MaybeHandle<BigInt> BitwiseOr(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y);
// Other parts of the public interface.
static MaybeHandle<BigInt> Increment(Isolate* isolate, Handle<BigInt> x);
static MaybeHandle<BigInt> Decrement(Isolate* isolate, Handle<BigInt> x);
bool ToBoolean() { return !is_zero(); }
uint32_t Hash() {
// TODO(jkummerow): Improve this. At least use length and sign.
return is_zero() ? 0 : ComputeIntegerHash(static_cast<uint32_t>(digit(0)));
}
static bool EqualToString(Isolate* isolate, Handle<BigInt> x,
Handle<String> y);
static bool EqualToNumber(Handle<BigInt> x, Handle<Object> y);
static ComparisonResult CompareToString(Isolate* isolate, Handle<BigInt> x,
Handle<String> y);
static ComparisonResult CompareToNumber(Handle<BigInt> x, Handle<Object> y);
// Exposed for tests, do not call directly. Use CompareToNumber() instead.
static ComparisonResult CompareToDouble(Handle<BigInt> x, double y);
static Handle<BigInt> AsIntN(Isolate* isolate, uint64_t n, Handle<BigInt> x);
static MaybeHandle<BigInt> AsUintN(Isolate* isolate, uint64_t n,
Handle<BigInt> x);
static Handle<BigInt> FromInt64(Isolate* isolate, int64_t n);
static Handle<BigInt> FromUint64(Isolate* isolate, uint64_t n);
static MaybeHandle<BigInt> FromWords64(Isolate* isolate, int sign_bit,
int words64_count,
const uint64_t* words);
int64_t AsInt64(bool* lossless = nullptr);
uint64_t AsUint64(bool* lossless = nullptr);
int Words64Count();
void ToWordsArray64(int* sign_bit, int* words64_count, uint64_t* words);
DECL_CAST(BigInt)
DECL_VERIFIER(BigInt)
DECL_PRINTER(BigInt)
void BigIntShortPrint(std::ostream& os);
inline static int SizeFor(int length) {
return kHeaderSize + length * kDigitSize;
}
static MaybeHandle<String> ToString(Isolate* isolate, Handle<BigInt> bigint,
int radix = 10);
// "The Number value for x", see:
// https://tc39.github.io/ecma262/#sec-ecmascript-language-types-number-type
// Returns a Smi or HeapNumber.
static Handle<Object> ToNumber(Isolate* isolate, Handle<BigInt> x);
// ECMAScript's NumberToBigInt
static MaybeHandle<BigInt> FromNumber(Isolate* isolate,
Handle<Object> number);
// ECMAScript's ToBigInt (throws for Number input)
static MaybeHandle<BigInt> FromObject(Isolate* isolate, Handle<Object> obj);
class BodyDescriptor;
private:
friend class StringToBigIntHelper;
friend class ValueDeserializer;
friend class ValueSerializer;
// Special functions for StringToBigIntHelper:
static Handle<BigInt> Zero(Isolate* isolate);
static MaybeHandle<FreshlyAllocatedBigInt> AllocateFor(
Isolate* isolate, int radix, int charcount, ShouldThrow should_throw,
PretenureFlag pretenure);
static void InplaceMultiplyAdd(Handle<FreshlyAllocatedBigInt> x,
uintptr_t factor, uintptr_t summand);
static Handle<BigInt> Finalize(Handle<FreshlyAllocatedBigInt> x, bool sign);
// Special functions for ValueSerializer/ValueDeserializer:
uint32_t GetBitfieldForSerialization() const;
static int DigitsByteLengthForBitfield(uint32_t bitfield);
// Expects {storage} to have a length of at least
// {DigitsByteLengthForBitfield(GetBitfieldForSerialization())}.
void SerializeDigits(uint8_t* storage);
V8_WARN_UNUSED_RESULT static MaybeHandle<BigInt> FromSerializedDigits(
Isolate* isolate, uint32_t bitfield, Vector<const uint8_t> digits_storage,
PretenureFlag pretenure);
DISALLOW_IMPLICIT_CONSTRUCTORS(BigInt);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_BIGINT_H_