[bigint] Implement Add, Subtract, UnaryMinus
Bug: v8:6791 Change-Id: I058db23c03451dc5028c3d39af8607d31048295c Reviewed-on: https://chromium-review.googlesource.com/667809 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#48075}
This commit is contained in:
parent
1bc42ab44c
commit
52531a6b96
@ -2,6 +2,21 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Parts of the implementation below:
|
||||
|
||||
// Copyright (c) 2014 the Dart project authors. Please see the AUTHORS file [1]
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file [2].
|
||||
//
|
||||
// [1] https://github.com/dart-lang/sdk/blob/master/AUTHORS
|
||||
// [2] https://github.com/dart-lang/sdk/blob/master/LICENSE
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file [3].
|
||||
//
|
||||
// [3] https://golang.org/LICENSE
|
||||
|
||||
#include "src/objects/bigint.h"
|
||||
|
||||
#include "src/objects-inl.h"
|
||||
@ -10,7 +25,13 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
Handle<BigInt> BigInt::UnaryMinus(Handle<BigInt> x) {
|
||||
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
|
||||
// Special case: There is no -0n.
|
||||
if (x->is_zero()) {
|
||||
return x;
|
||||
}
|
||||
Handle<BigInt> result = BigInt::Copy(x);
|
||||
result->set_sign(!x->sign());
|
||||
return result;
|
||||
}
|
||||
|
||||
Handle<BigInt> BigInt::BitwiseNot(Handle<BigInt> x) {
|
||||
@ -35,11 +56,33 @@ MaybeHandle<BigInt> BigInt::Remainder(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
}
|
||||
|
||||
Handle<BigInt> BigInt::Add(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
|
||||
bool xsign = x->sign();
|
||||
if (xsign == y->sign()) {
|
||||
// x + y == x + y
|
||||
// -x + -y == -(x + y)
|
||||
return AbsoluteAdd(x, y, xsign);
|
||||
}
|
||||
// x + -y == x - y == -(y - x)
|
||||
// -x + y == y - x == -(x - y)
|
||||
if (AbsoluteCompare(x, y) >= 0) {
|
||||
return AbsoluteSub(x, y, xsign);
|
||||
}
|
||||
return AbsoluteSub(y, x, !xsign);
|
||||
}
|
||||
|
||||
Handle<BigInt> BigInt::Subtract(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
|
||||
bool xsign = x->sign();
|
||||
if (xsign != y->sign()) {
|
||||
// x - (-y) == x + y
|
||||
// (-x) - y == -(x + y)
|
||||
return AbsoluteAdd(x, y, xsign);
|
||||
}
|
||||
// x - y == -(y - x)
|
||||
// (-x) - (-y) == y - x == -(x - y)
|
||||
if (AbsoluteCompare(x, y) >= 0) {
|
||||
return AbsoluteSub(x, y, xsign);
|
||||
}
|
||||
return AbsoluteSub(y, x, !xsign);
|
||||
}
|
||||
|
||||
Handle<BigInt> BigInt::LeftShift(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
@ -83,7 +126,7 @@ Handle<BigInt> BigInt::BitwiseOr(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
Handle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) {
|
||||
// TODO(jkummerow): Support non-power-of-two radixes.
|
||||
if (!base::bits::IsPowerOfTwo(radix)) radix = 16;
|
||||
return bigint->ToStringBasePowerOfTwo(bigint, radix);
|
||||
return ToStringBasePowerOfTwo(bigint, radix);
|
||||
}
|
||||
|
||||
void BigInt::Initialize(int length, bool zero_initialize) {
|
||||
@ -104,6 +147,105 @@ void BigInt::Initialize(int length, bool zero_initialize) {
|
||||
|
||||
// Private helpers for public methods.
|
||||
|
||||
Handle<BigInt> BigInt::AbsoluteAdd(Handle<BigInt> x, Handle<BigInt> y,
|
||||
bool result_sign) {
|
||||
if (x->length() < y->length()) return AbsoluteAdd(y, x, result_sign);
|
||||
if (x->is_zero()) {
|
||||
DCHECK(y->is_zero());
|
||||
return x;
|
||||
}
|
||||
if (y->is_zero()) {
|
||||
return result_sign == x->sign() ? x : UnaryMinus(x);
|
||||
}
|
||||
Handle<BigInt> result =
|
||||
x->GetIsolate()->factory()->NewBigIntRaw(x->length() + 1);
|
||||
digit_t carry = 0;
|
||||
int i = 0;
|
||||
for (; i < y->length(); i++) {
|
||||
digit_t new_carry = 0;
|
||||
digit_t sum = digit_add(x->digit(i), y->digit(i), &new_carry);
|
||||
sum = digit_add(sum, carry, &new_carry);
|
||||
result->set_digit(i, sum);
|
||||
carry = new_carry;
|
||||
}
|
||||
for (; i < x->length(); i++) {
|
||||
digit_t new_carry = 0;
|
||||
digit_t sum = digit_add(x->digit(i), carry, &new_carry);
|
||||
result->set_digit(i, sum);
|
||||
carry = new_carry;
|
||||
}
|
||||
result->set_digit(i, carry);
|
||||
result->set_sign(result_sign);
|
||||
result->RightTrim();
|
||||
return result;
|
||||
}
|
||||
|
||||
Handle<BigInt> BigInt::AbsoluteSub(Handle<BigInt> x, Handle<BigInt> y,
|
||||
bool result_sign) {
|
||||
DCHECK(x->length() >= y->length());
|
||||
SLOW_DCHECK(AbsoluteCompare(x, y) >= 0);
|
||||
if (x->is_zero()) {
|
||||
DCHECK(y->is_zero());
|
||||
return x;
|
||||
}
|
||||
if (y->is_zero()) {
|
||||
return result_sign == x->sign() ? x : UnaryMinus(x);
|
||||
}
|
||||
Handle<BigInt> result = x->GetIsolate()->factory()->NewBigIntRaw(x->length());
|
||||
digit_t borrow = 0;
|
||||
int i = 0;
|
||||
for (; i < y->length(); i++) {
|
||||
digit_t new_borrow = 0;
|
||||
digit_t difference = digit_sub(x->digit(i), y->digit(i), &new_borrow);
|
||||
difference = digit_sub(difference, borrow, &new_borrow);
|
||||
result->set_digit(i, difference);
|
||||
borrow = new_borrow;
|
||||
}
|
||||
for (; i < x->length(); i++) {
|
||||
digit_t new_borrow = 0;
|
||||
digit_t difference = digit_sub(x->digit(i), borrow, &new_borrow);
|
||||
result->set_digit(i, difference);
|
||||
borrow = new_borrow;
|
||||
}
|
||||
DCHECK_EQ(0, borrow);
|
||||
result->set_sign(result_sign);
|
||||
result->RightTrim();
|
||||
return result;
|
||||
}
|
||||
|
||||
int BigInt::AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
int diff = x->length() - y->length();
|
||||
if (diff != 0) return diff;
|
||||
int i = x->length() - 1;
|
||||
while (i >= 0 && x->digit(i) == y->digit(i)) i--;
|
||||
if (i < 0) return 0;
|
||||
return x->digit(i) > y->digit(i) ? 1 : -1;
|
||||
}
|
||||
|
||||
Handle<BigInt> BigInt::Copy(Handle<BigInt> source) {
|
||||
int length = source->length();
|
||||
Handle<BigInt> result = source->GetIsolate()->factory()->NewBigIntRaw(length);
|
||||
memcpy(result->address() + HeapObject::kHeaderSize,
|
||||
source->address() + HeapObject::kHeaderSize,
|
||||
SizeFor(length) - HeapObject::kHeaderSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
void BigInt::RightTrim() {
|
||||
int old_length = length();
|
||||
int new_length = old_length;
|
||||
while (digit(new_length - 1) == 0) new_length--;
|
||||
int to_trim = old_length - new_length;
|
||||
if (to_trim == 0) return;
|
||||
int size_delta = to_trim * kDigitSize;
|
||||
Address new_end = this->address() + SizeFor(new_length);
|
||||
Heap* heap = GetHeap();
|
||||
heap->CreateFillerObjectAt(new_end, size_delta, ClearRecordedSlots::kNo);
|
||||
// Canonicalize -0n.
|
||||
if (new_length == 0) set_sign(false);
|
||||
set_length(new_length);
|
||||
}
|
||||
|
||||
static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
// TODO(jkummerow): Add more tests for this when it is exposed on
|
||||
@ -114,7 +256,7 @@ Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) {
|
||||
DCHECK(radix >= 2 && radix <= 32);
|
||||
Factory* factory = x->GetIsolate()->factory();
|
||||
// TODO(jkummerow): check in caller?
|
||||
if (is_zero()) return factory->NewStringFromStaticChars("0");
|
||||
if (x->is_zero()) return factory->NewStringFromStaticChars("0");
|
||||
|
||||
const int len = x->length();
|
||||
const bool sign = x->sign();
|
||||
@ -128,6 +270,9 @@ Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) {
|
||||
chars_for_msd++;
|
||||
}
|
||||
// All other digits need chars_per_digit characters; a leading "-" needs one.
|
||||
if ((String::kMaxLength - chars_for_msd - sign) / chars_per_digit < len - 1) {
|
||||
CHECK(false); // TODO(jkummerow): Throw instead of crashing.
|
||||
}
|
||||
const int chars = chars_for_msd + (len - 1) * chars_per_digit + sign;
|
||||
|
||||
Handle<SeqOneByteString> result =
|
||||
@ -151,6 +296,48 @@ Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Digit arithmetic helpers.
|
||||
|
||||
#if V8_TARGET_ARCH_32_BIT
|
||||
#define HAVE_TWODIGIT_T 1
|
||||
typedef uint64_t twodigit_t;
|
||||
#elif defined(__SIZEOF_INT128__)
|
||||
// Both Clang and GCC support this on x64.
|
||||
#define HAVE_TWODIGIT_T 1
|
||||
typedef __uint128_t twodigit_t;
|
||||
#endif
|
||||
|
||||
// {carry} must point to an initialized digit_t and will either be incremented
|
||||
// by one or left alone.
|
||||
inline BigInt::digit_t BigInt::digit_add(digit_t a, digit_t b, digit_t* carry) {
|
||||
#if HAVE_TWODIGIT_T
|
||||
twodigit_t result = static_cast<twodigit_t>(a) + static_cast<twodigit_t>(b);
|
||||
*carry += result >> kDigitBits;
|
||||
return static_cast<digit_t>(result);
|
||||
#else
|
||||
digit_t result = a + b;
|
||||
if (result < a) *carry += 1;
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
// {borrow} must point to an initialized digit_t and will either be incremented
|
||||
// by one or left alone.
|
||||
inline BigInt::digit_t BigInt::digit_sub(digit_t a, digit_t b,
|
||||
digit_t* borrow) {
|
||||
#if HAVE_TWODIGIT_T
|
||||
twodigit_t result = static_cast<twodigit_t>(a) - static_cast<twodigit_t>(b);
|
||||
*borrow += (result >> kDigitBits) & 1;
|
||||
return static_cast<digit_t>(result);
|
||||
#else
|
||||
digit_t result = a - b;
|
||||
if (result > a) *borrow += 1;
|
||||
return static_cast<digit_t>(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef HAVE_TWODIGIT_T
|
||||
|
||||
#ifdef OBJECT_PRINT
|
||||
void BigInt::BigIntPrint(std::ostream& os) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
@ -89,7 +89,22 @@ class BigInt : public HeapObject {
|
||||
static const digit_t kHalfDigitMask = (1ull << kHalfDigitBits) - 1;
|
||||
|
||||
// Private helpers for public methods.
|
||||
Handle<String> ToStringBasePowerOfTwo(Handle<BigInt> x, int radix);
|
||||
static Handle<BigInt> Copy(Handle<BigInt> source);
|
||||
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 Handle<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);
|
||||
|
||||
class LengthBits : public BitField<int, 0, kMaxLengthBits> {};
|
||||
class SignBits : public BitField<bool, LengthBits::kNext, 1> {};
|
||||
|
Loading…
Reference in New Issue
Block a user