[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
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// 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/bigint.h"
|
||||||
|
|
||||||
#include "src/objects-inl.h"
|
#include "src/objects-inl.h"
|
||||||
@ -10,7 +25,13 @@ namespace v8 {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
Handle<BigInt> BigInt::UnaryMinus(Handle<BigInt> x) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
Handle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) {
|
||||||
// TODO(jkummerow): Support non-power-of-two radixes.
|
// TODO(jkummerow): Support non-power-of-two radixes.
|
||||||
if (!base::bits::IsPowerOfTwo(radix)) radix = 16;
|
if (!base::bits::IsPowerOfTwo(radix)) radix = 16;
|
||||||
return bigint->ToStringBasePowerOfTwo(bigint, radix);
|
return ToStringBasePowerOfTwo(bigint, radix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigInt::Initialize(int length, bool zero_initialize) {
|
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.
|
// 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";
|
static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
// TODO(jkummerow): Add more tests for this when it is exposed on
|
// 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);
|
DCHECK(radix >= 2 && radix <= 32);
|
||||||
Factory* factory = x->GetIsolate()->factory();
|
Factory* factory = x->GetIsolate()->factory();
|
||||||
// TODO(jkummerow): check in caller?
|
// 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 int len = x->length();
|
||||||
const bool sign = x->sign();
|
const bool sign = x->sign();
|
||||||
@ -128,6 +270,9 @@ Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) {
|
|||||||
chars_for_msd++;
|
chars_for_msd++;
|
||||||
}
|
}
|
||||||
// All other digits need chars_per_digit characters; a leading "-" needs one.
|
// 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;
|
const int chars = chars_for_msd + (len - 1) * chars_per_digit + sign;
|
||||||
|
|
||||||
Handle<SeqOneByteString> result =
|
Handle<SeqOneByteString> result =
|
||||||
@ -151,6 +296,48 @@ Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) {
|
|||||||
return result;
|
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
|
#ifdef OBJECT_PRINT
|
||||||
void BigInt::BigIntPrint(std::ostream& os) {
|
void BigInt::BigIntPrint(std::ostream& os) {
|
||||||
DisallowHeapAllocation no_gc;
|
DisallowHeapAllocation no_gc;
|
||||||
|
@ -89,7 +89,22 @@ class BigInt : public HeapObject {
|
|||||||
static const digit_t kHalfDigitMask = (1ull << kHalfDigitBits) - 1;
|
static const digit_t kHalfDigitMask = (1ull << kHalfDigitBits) - 1;
|
||||||
|
|
||||||
// Private helpers for public methods.
|
// 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 LengthBits : public BitField<int, 0, kMaxLengthBits> {};
|
||||||
class SignBits : public BitField<bool, LengthBits::kNext, 1> {};
|
class SignBits : public BitField<bool, LengthBits::kNext, 1> {};
|
||||||
|
Loading…
Reference in New Issue
Block a user