blob: 1de2008b0c3e827a9831a45039db849b37f49ff1 [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 {
// UNDER CONSTRUCTION!
// Arbitrary precision integers in JavaScript.
class BigInt : public HeapObject {
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(Handle<BigInt> x);
static Handle<BigInt> BitwiseNot(Handle<BigInt> x);
static MaybeHandle<BigInt> Exponentiate(Handle<BigInt> base,
Handle<BigInt> exponent);
static Handle<BigInt> Multiply(Handle<BigInt> x, Handle<BigInt> y);
static MaybeHandle<BigInt> Divide(Handle<BigInt> x, Handle<BigInt> y);
static MaybeHandle<BigInt> Remainder(Handle<BigInt> x, Handle<BigInt> y);
static Handle<BigInt> Add(Handle<BigInt> x, Handle<BigInt> y);
static Handle<BigInt> Subtract(Handle<BigInt> x, Handle<BigInt> y);
static Handle<BigInt> LeftShift(Handle<BigInt> x, Handle<BigInt> y);
static Handle<BigInt> SignedRightShift(Handle<BigInt> x, Handle<BigInt> y);
static MaybeHandle<BigInt> UnsignedRightShift(Handle<BigInt> x,
Handle<BigInt> y);
static bool LessThan(Handle<BigInt> x, Handle<BigInt> y);
static bool Equal(BigInt* x, BigInt* y);
static Handle<BigInt> BitwiseAnd(Handle<BigInt> x, Handle<BigInt> y);
static Handle<BigInt> BitwiseXor(Handle<BigInt> x, Handle<BigInt> y);
static Handle<BigInt> BitwiseOr(Handle<BigInt> x, Handle<BigInt> y);
// Other parts of the public interface.
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)));
}
DECL_CAST(BigInt)
DECL_VERIFIER(BigInt)
DECL_PRINTER(BigInt)
// TODO(jkummerow): Do we need {synchronized_length} for GC purposes?
DECL_INT_ACCESSORS(length)
inline static int SizeFor(int length) {
return kHeaderSize + length * kDigitSize;
}
void Initialize(int length, bool zero_initialize);
static MaybeHandle<String> ToString(Handle<BigInt> bigint, int radix);
// Temporarily exposed helper, pending proper initialization.
void set_value(int value) {
DCHECK(length() == 1);
if (value > 0) {
set_digit(0, value);
} else {
set_digit(0, -value); // This can overflow. We don't care.
set_sign(true);
}
}
// The maximum length that the current implementation supports would be
// kMaxInt / kDigitBits. However, we use a lower limit for now, because
// raising it later is easier than lowering it.
static const int kMaxLengthBits = 20;
static const int kMaxLength = (1 << kMaxLengthBits) - 1;
class BodyDescriptor;
private:
friend class BigIntParseIntHelper;
typedef uintptr_t digit_t;
static const int kDigitSize = sizeof(digit_t);
static const int kDigitBits = kDigitSize * kBitsPerByte;
static const int kHalfDigitBits = kDigitBits / 2;
static const digit_t kHalfDigitMask = (1ull << kHalfDigitBits) - 1;
// Private helpers for public methods.
static Handle<BigInt> Copy(Handle<BigInt> source);
static MaybeHandle<BigInt> AllocateFor(Isolate* isolate, int radix,
int charcount);
void RightTrim();
static Handle<BigInt> AbsoluteAdd(Handle<BigInt> x, Handle<BigInt> y,
bool result_sign);
static Handle<BigInt> AbsoluteSub(Handle<BigInt> x, Handle<BigInt> y,
bool result_sign);
// Returns a positive value if abs(x) > abs(y), a negative value if
// abs(x) < abs(y), or zero if abs(x) == abs(y).
static int AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y);
static void MultiplyAccumulate(Handle<BigInt> multiplicand,
digit_t multiplier, Handle<BigInt> accumulator,
int accumulator_index);
static void InternalMultiplyAdd(BigInt* source, digit_t factor,
digit_t summand, int n, BigInt* result);
void InplaceMultiplyAdd(uintptr_t factor, uintptr_t summand);
// Specialized helpers for Divide/Remainder.
static void AbsoluteDivSmall(Handle<BigInt> x, digit_t divisor,
Handle<BigInt>* quotient, digit_t* remainder);
static void AbsoluteDivLarge(Handle<BigInt> dividend, Handle<BigInt> divisor,
Handle<BigInt>* quotient,
Handle<BigInt>* remainder);
static bool ProductGreaterThan(digit_t factor1, digit_t factor2, digit_t high,
digit_t low);
digit_t InplaceAdd(BigInt* summand, int start_index);
digit_t InplaceSub(BigInt* subtrahend, int start_index);
void InplaceRightShift(int shift);
enum SpecialLeftShiftMode {
kSameSizeResult,
kAlwaysAddOneDigit,
};
static Handle<BigInt> SpecialLeftShift(Handle<BigInt> x, int shift,
SpecialLeftShiftMode mode);
static MaybeHandle<String> ToStringBasePowerOfTwo(Handle<BigInt> x,
int radix);
// Digit arithmetic helpers.
static inline digit_t digit_add(digit_t a, digit_t b, digit_t* carry);
static inline digit_t digit_sub(digit_t a, digit_t b, digit_t* borrow);
static inline digit_t digit_mul(digit_t a, digit_t b, digit_t* high);
static inline digit_t digit_div(digit_t high, digit_t low, digit_t divisor,
digit_t* remainder);
class LengthBits : public BitField<int, 0, kMaxLengthBits> {};
class SignBits : public BitField<bool, LengthBits::kNext, 1> {};
// Low-level accessors.
// sign() == true means negative.
DECL_BOOLEAN_ACCESSORS(sign)
inline digit_t digit(int n) const;
inline void set_digit(int n, digit_t value);
bool is_zero() {
DCHECK(length() > 0 || !sign()); // There is no -0n.
return length() == 0;
}
static const int kBitfieldOffset = HeapObject::kHeaderSize;
static const int kDigitsOffset = kBitfieldOffset + kPointerSize;
static const int kHeaderSize = kDigitsOffset;
DISALLOW_IMPLICIT_CONSTRUCTORS(BigInt);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_BIGINT_H_