Commit f83d0e0b authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Implement shift ops

Bug: v8:6791
Change-Id: I5e91832bcb74e895eaf7a3d6ee493c832abba7bf
Reviewed-on: https://chromium-review.googlesource.com/699635
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48299}
parent c5625884
......@@ -275,6 +275,7 @@ class ErrorUtils : public AllStatic {
"The comparison function must be either a function or undefined") \
T(BigIntMixedTypes, \
"Cannot mix BigInt and other types, use explicit conversions") \
T(BigIntShr, "BigInts have no unsigned right shift, use >> instead") \
T(CalledNonCallable, "% is not a function") \
T(CalledOnNonObject, "% called on non-object") \
T(CalledOnNullOrUndefined, "% called on null or undefined") \
......
......@@ -136,17 +136,23 @@ Handle<BigInt> BigInt::Subtract(Handle<BigInt> x, Handle<BigInt> y) {
return AbsoluteSub(y, x, !xsign);
}
Handle<BigInt> BigInt::LeftShift(Handle<BigInt> x, Handle<BigInt> y) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
MaybeHandle<BigInt> BigInt::LeftShift(Handle<BigInt> x, Handle<BigInt> y) {
if (y->is_zero() || x->is_zero()) return x;
if (y->sign()) return RightShiftByAbsolute(x, y);
return LeftShiftByAbsolute(x, y);
}
Handle<BigInt> BigInt::SignedRightShift(Handle<BigInt> x, Handle<BigInt> y) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
MaybeHandle<BigInt> BigInt::SignedRightShift(Handle<BigInt> x,
Handle<BigInt> y) {
if (y->is_zero() || x->is_zero()) return x;
if (y->sign()) return LeftShiftByAbsolute(x, y);
return RightShiftByAbsolute(x, y);
}
MaybeHandle<BigInt> BigInt::UnsignedRightShift(Handle<BigInt> x,
Handle<BigInt> y) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
THROW_NEW_ERROR(x->GetIsolate(), NewTypeError(MessageTemplate::kBigIntShr),
BigInt);
}
bool BigInt::LessThan(Handle<BigInt> x, Handle<BigInt> y) {
......@@ -770,6 +776,144 @@ Handle<BigInt> BigInt::SpecialLeftShift(Handle<BigInt> x, int shift,
return result;
}
MaybeHandle<BigInt> BigInt::LeftShiftByAbsolute(Handle<BigInt> x,
Handle<BigInt> y) {
Isolate* isolate = x->GetIsolate();
Maybe<digit_t> maybe_shift = ToShiftAmount(y);
if (maybe_shift.IsNothing()) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
BigInt);
}
digit_t shift = maybe_shift.FromJust();
int digit_shift = static_cast<int>(shift / kDigitBits);
int bits_shift = static_cast<int>(shift % kDigitBits);
int length = x->length();
bool grow = bits_shift != 0 &&
(x->digit(length - 1) >> (kDigitBits - bits_shift)) != 0;
int result_length = length + digit_shift + grow;
if (result_length > kMaxLength) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
BigInt);
}
Handle<BigInt> result = isolate->factory()->NewBigIntRaw(result_length);
if (bits_shift == 0) {
int i = 0;
for (; i < digit_shift; i++) result->set_digit(i, 0ul);
for (; i < result_length; i++) {
result->set_digit(i, x->digit(i - digit_shift));
}
} else {
digit_t carry = 0;
for (int i = 0; i < digit_shift; i++) result->set_digit(i, 0ul);
for (int i = 0; i < length; i++) {
digit_t d = x->digit(i);
result->set_digit(i + digit_shift, (d << bits_shift) | carry);
carry = d >> (kDigitBits - bits_shift);
}
if (grow) {
result->set_digit(length + digit_shift, carry);
} else {
DCHECK(carry == 0);
}
}
result->set_sign(x->sign());
result->RightTrim();
return result;
}
Handle<BigInt> BigInt::RightShiftByAbsolute(Handle<BigInt> x,
Handle<BigInt> y) {
Isolate* isolate = x->GetIsolate();
int length = x->length();
bool sign = x->sign();
Maybe<digit_t> maybe_shift = ToShiftAmount(y);
if (maybe_shift.IsNothing()) {
return RightShiftByMaximum(isolate, sign);
}
digit_t shift = maybe_shift.FromJust();
int digit_shift = static_cast<int>(shift / kDigitBits);
int bits_shift = static_cast<int>(shift % kDigitBits);
int result_length = length - digit_shift;
if (result_length <= 0) {
return RightShiftByMaximum(isolate, sign);
}
// For negative numbers, round down if any bit was shifted out (so that e.g.
// -5n >> 1n == -3n and not -2n). Check now whether this will happen and
// whether it can cause overflow into a new digit. If we allocate the result
// large enough up front, it avoids having to do a second allocation later.
bool must_round_down = false;
if (sign) {
if ((x->digit(digit_shift) & ((1 << bits_shift) - 1)) != 0) {
must_round_down = true;
} else {
for (int i = 0; i < digit_shift; i++) {
if (x->digit(i) != 0) {
must_round_down = true;
break;
}
}
}
}
// If bits_shift is non-zero, it frees up bits, preventing overflow.
if (must_round_down && bits_shift == 0) {
// Overflow cannot happen if the most significant digit has unset bits.
digit_t msd = x->digit(length - 1);
bool rounding_can_overflow = digit_ismax(msd);
if (rounding_can_overflow) result_length++;
}
Handle<BigInt> result = isolate->factory()->NewBigIntRaw(result_length);
if (bits_shift == 0) {
for (int i = digit_shift; i < length; i++) {
result->set_digit(i - digit_shift, x->digit(i));
}
} else {
digit_t carry = x->digit(digit_shift) >> bits_shift;
int last = length - digit_shift - 1;
for (int i = 0; i < last; i++) {
digit_t d = x->digit(i + digit_shift + 1);
result->set_digit(i, (d << (kDigitBits - bits_shift)) | carry);
carry = d >> bits_shift;
}
result->set_digit(last, carry);
}
if (sign) {
result->set_sign(true);
if (must_round_down) {
// Since the result is negative, rounding down means adding one to
// its absolute value.
result = AbsoluteAddOne(result, true, *result);
}
}
result->RightTrim();
return result;
}
Handle<BigInt> BigInt::RightShiftByMaximum(Isolate* isolate, bool sign) {
if (sign) {
// Return -1n.
// TODO(jkummerow): Consider caching a canonical -1n BigInt.
Handle<BigInt> result = isolate->factory()->NewBigInt(1);
result->set_digit(0, 1);
result->set_sign(true);
return result;
} else {
// TODO(jkummerow): Consider caching a canonical zero BigInt.
return isolate->factory()->NewBigInt(0);
}
}
// Returns the value of {x} if it is less than the maximum bit length of
// a BigInt, or Nothing otherwise.
Maybe<BigInt::digit_t> BigInt::ToShiftAmount(Handle<BigInt> x) {
if (x->length() > 1) return Nothing<digit_t>();
digit_t value = x->digit(0);
STATIC_ASSERT(kMaxLength * kDigitBits < std::numeric_limits<digit_t>::max());
if (value > kMaxLength * kDigitBits) return Nothing<digit_t>();
return Just(value);
}
Handle<BigInt> BigInt::Copy(Handle<BigInt> source) {
int length = source->length();
Handle<BigInt> result = source->GetIsolate()->factory()->NewBigIntRaw(length);
......
......@@ -31,8 +31,9 @@ class BigInt : public HeapObject {
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> LeftShift(Handle<BigInt> x, Handle<BigInt> y);
static MaybeHandle<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);
......@@ -146,6 +147,14 @@ class BigInt : public HeapObject {
static Handle<BigInt> SpecialLeftShift(Handle<BigInt> x, int shift,
SpecialLeftShiftMode mode);
// Specialized helpers for shift operations.
static MaybeHandle<BigInt> LeftShiftByAbsolute(Handle<BigInt> x,
Handle<BigInt> y);
static Handle<BigInt> RightShiftByAbsolute(Handle<BigInt> x,
Handle<BigInt> y);
static Handle<BigInt> RightShiftByMaximum(Isolate* isolate, bool sign);
static Maybe<digit_t> ToShiftAmount(Handle<BigInt> x);
static MaybeHandle<String> ToStringBasePowerOfTwo(Handle<BigInt> x,
int radix);
......
......@@ -428,7 +428,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(18),
B(LdaConstant), U8(16),
B(Star), R(19),
......
......@@ -143,7 +143,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -432,7 +432,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -743,7 +743,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -991,7 +991,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......
......@@ -86,7 +86,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -227,7 +227,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -380,7 +380,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -523,7 +523,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(10),
B(LdaConstant), U8(10),
B(Star), R(11),
......
......@@ -90,7 +90,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(13),
B(LdaConstant), U8(7),
B(Star), R(14),
......@@ -268,7 +268,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(13),
B(LdaConstant), U8(11),
B(Star), R(14),
......@@ -422,7 +422,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(11),
B(LdaConstant), U8(9),
B(Star), R(12),
......@@ -524,7 +524,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(65),
B(LdaSmi), I8(66),
B(Star), R(17),
B(LdaConstant), U8(4),
B(Star), R(18),
......@@ -580,7 +580,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(16),
B(LdaConstant), U8(9),
B(Star), R(17),
......@@ -754,7 +754,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......@@ -953,7 +953,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(15),
B(LdaConstant), U8(14),
B(Star), R(16),
......@@ -1116,7 +1116,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(20),
B(LdaConstant), U8(7),
B(Star), R(21),
......@@ -1358,7 +1358,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(20),
B(LdaConstant), U8(9),
B(Star), R(21),
......
......@@ -257,7 +257,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(136),
B(Wide), B(LdaSmi), I16(137),
B(Star), R(14),
B(LdaConstant), U8(15),
B(Star), R(15),
......
......@@ -231,7 +231,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(65),
B(LdaSmi), I8(66),
B(Star), R(4),
B(LdaConstant), U8(1),
B(Star), R(5),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment