Skip to content

Commit f83d0e0

Browse files
jakobkummerowCommit Bot
authored andcommitted
[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: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/master@{#48299}
1 parent c562588 commit f83d0e0

9 files changed

Lines changed: 181 additions & 27 deletions

File tree

src/messages.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ class ErrorUtils : public AllStatic {
275275
"The comparison function must be either a function or undefined") \
276276
T(BigIntMixedTypes, \
277277
"Cannot mix BigInt and other types, use explicit conversions") \
278+
T(BigIntShr, "BigInts have no unsigned right shift, use >> instead") \
278279
T(CalledNonCallable, "% is not a function") \
279280
T(CalledOnNonObject, "% called on non-object") \
280281
T(CalledOnNullOrUndefined, "% called on null or undefined") \

src/objects/bigint.cc

Lines changed: 149 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,23 @@ Handle<BigInt> BigInt::Subtract(Handle<BigInt> x, Handle<BigInt> y) {
136136
return AbsoluteSub(y, x, !xsign);
137137
}
138138

139-
Handle<BigInt> BigInt::LeftShift(Handle<BigInt> x, Handle<BigInt> y) {
140-
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
139+
MaybeHandle<BigInt> BigInt::LeftShift(Handle<BigInt> x, Handle<BigInt> y) {
140+
if (y->is_zero() || x->is_zero()) return x;
141+
if (y->sign()) return RightShiftByAbsolute(x, y);
142+
return LeftShiftByAbsolute(x, y);
141143
}
142144

143-
Handle<BigInt> BigInt::SignedRightShift(Handle<BigInt> x, Handle<BigInt> y) {
144-
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
145+
MaybeHandle<BigInt> BigInt::SignedRightShift(Handle<BigInt> x,
146+
Handle<BigInt> y) {
147+
if (y->is_zero() || x->is_zero()) return x;
148+
if (y->sign()) return LeftShiftByAbsolute(x, y);
149+
return RightShiftByAbsolute(x, y);
145150
}
146151

147152
MaybeHandle<BigInt> BigInt::UnsignedRightShift(Handle<BigInt> x,
148153
Handle<BigInt> y) {
149-
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
154+
THROW_NEW_ERROR(x->GetIsolate(), NewTypeError(MessageTemplate::kBigIntShr),
155+
BigInt);
150156
}
151157

152158
bool BigInt::LessThan(Handle<BigInt> x, Handle<BigInt> y) {
@@ -770,6 +776,144 @@ Handle<BigInt> BigInt::SpecialLeftShift(Handle<BigInt> x, int shift,
770776
return result;
771777
}
772778

779+
MaybeHandle<BigInt> BigInt::LeftShiftByAbsolute(Handle<BigInt> x,
780+
Handle<BigInt> y) {
781+
Isolate* isolate = x->GetIsolate();
782+
Maybe<digit_t> maybe_shift = ToShiftAmount(y);
783+
if (maybe_shift.IsNothing()) {
784+
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
785+
BigInt);
786+
}
787+
digit_t shift = maybe_shift.FromJust();
788+
int digit_shift = static_cast<int>(shift / kDigitBits);
789+
int bits_shift = static_cast<int>(shift % kDigitBits);
790+
int length = x->length();
791+
bool grow = bits_shift != 0 &&
792+
(x->digit(length - 1) >> (kDigitBits - bits_shift)) != 0;
793+
int result_length = length + digit_shift + grow;
794+
if (result_length > kMaxLength) {
795+
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
796+
BigInt);
797+
}
798+
Handle<BigInt> result = isolate->factory()->NewBigIntRaw(result_length);
799+
if (bits_shift == 0) {
800+
int i = 0;
801+
for (; i < digit_shift; i++) result->set_digit(i, 0ul);
802+
for (; i < result_length; i++) {
803+
result->set_digit(i, x->digit(i - digit_shift));
804+
}
805+
} else {
806+
digit_t carry = 0;
807+
for (int i = 0; i < digit_shift; i++) result->set_digit(i, 0ul);
808+
for (int i = 0; i < length; i++) {
809+
digit_t d = x->digit(i);
810+
result->set_digit(i + digit_shift, (d << bits_shift) | carry);
811+
carry = d >> (kDigitBits - bits_shift);
812+
}
813+
if (grow) {
814+
result->set_digit(length + digit_shift, carry);
815+
} else {
816+
DCHECK(carry == 0);
817+
}
818+
}
819+
result->set_sign(x->sign());
820+
result->RightTrim();
821+
return result;
822+
}
823+
824+
Handle<BigInt> BigInt::RightShiftByAbsolute(Handle<BigInt> x,
825+
Handle<BigInt> y) {
826+
Isolate* isolate = x->GetIsolate();
827+
int length = x->length();
828+
bool sign = x->sign();
829+
Maybe<digit_t> maybe_shift = ToShiftAmount(y);
830+
if (maybe_shift.IsNothing()) {
831+
return RightShiftByMaximum(isolate, sign);
832+
}
833+
digit_t shift = maybe_shift.FromJust();
834+
int digit_shift = static_cast<int>(shift / kDigitBits);
835+
int bits_shift = static_cast<int>(shift % kDigitBits);
836+
int result_length = length - digit_shift;
837+
if (result_length <= 0) {
838+
return RightShiftByMaximum(isolate, sign);
839+
}
840+
// For negative numbers, round down if any bit was shifted out (so that e.g.
841+
// -5n >> 1n == -3n and not -2n). Check now whether this will happen and
842+
// whether it can cause overflow into a new digit. If we allocate the result
843+
// large enough up front, it avoids having to do a second allocation later.
844+
bool must_round_down = false;
845+
if (sign) {
846+
if ((x->digit(digit_shift) & ((1 << bits_shift) - 1)) != 0) {
847+
must_round_down = true;
848+
} else {
849+
for (int i = 0; i < digit_shift; i++) {
850+
if (x->digit(i) != 0) {
851+
must_round_down = true;
852+
break;
853+
}
854+
}
855+
}
856+
}
857+
// If bits_shift is non-zero, it frees up bits, preventing overflow.
858+
if (must_round_down && bits_shift == 0) {
859+
// Overflow cannot happen if the most significant digit has unset bits.
860+
digit_t msd = x->digit(length - 1);
861+
bool rounding_can_overflow = digit_ismax(msd);
862+
if (rounding_can_overflow) result_length++;
863+
}
864+
865+
Handle<BigInt> result = isolate->factory()->NewBigIntRaw(result_length);
866+
if (bits_shift == 0) {
867+
for (int i = digit_shift; i < length; i++) {
868+
result->set_digit(i - digit_shift, x->digit(i));
869+
}
870+
} else {
871+
digit_t carry = x->digit(digit_shift) >> bits_shift;
872+
int last = length - digit_shift - 1;
873+
for (int i = 0; i < last; i++) {
874+
digit_t d = x->digit(i + digit_shift + 1);
875+
result->set_digit(i, (d << (kDigitBits - bits_shift)) | carry);
876+
carry = d >> bits_shift;
877+
}
878+
result->set_digit(last, carry);
879+
}
880+
881+
if (sign) {
882+
result->set_sign(true);
883+
if (must_round_down) {
884+
// Since the result is negative, rounding down means adding one to
885+
// its absolute value.
886+
result = AbsoluteAddOne(result, true, *result);
887+
}
888+
}
889+
result->RightTrim();
890+
return result;
891+
}
892+
893+
Handle<BigInt> BigInt::RightShiftByMaximum(Isolate* isolate, bool sign) {
894+
if (sign) {
895+
// Return -1n.
896+
// TODO(jkummerow): Consider caching a canonical -1n BigInt.
897+
Handle<BigInt> result = isolate->factory()->NewBigInt(1);
898+
result->set_digit(0, 1);
899+
result->set_sign(true);
900+
return result;
901+
} else {
902+
// TODO(jkummerow): Consider caching a canonical zero BigInt.
903+
return isolate->factory()->NewBigInt(0);
904+
}
905+
}
906+
907+
// Returns the value of {x} if it is less than the maximum bit length of
908+
// a BigInt, or Nothing otherwise.
909+
Maybe<BigInt::digit_t> BigInt::ToShiftAmount(Handle<BigInt> x) {
910+
if (x->length() > 1) return Nothing<digit_t>();
911+
digit_t value = x->digit(0);
912+
STATIC_ASSERT(kMaxLength * kDigitBits < std::numeric_limits<digit_t>::max());
913+
if (value > kMaxLength * kDigitBits) return Nothing<digit_t>();
914+
return Just(value);
915+
}
916+
773917
Handle<BigInt> BigInt::Copy(Handle<BigInt> source) {
774918
int length = source->length();
775919
Handle<BigInt> result = source->GetIsolate()->factory()->NewBigIntRaw(length);

src/objects/bigint.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ class BigInt : public HeapObject {
3131
static MaybeHandle<BigInt> Remainder(Handle<BigInt> x, Handle<BigInt> y);
3232
static Handle<BigInt> Add(Handle<BigInt> x, Handle<BigInt> y);
3333
static Handle<BigInt> Subtract(Handle<BigInt> x, Handle<BigInt> y);
34-
static Handle<BigInt> LeftShift(Handle<BigInt> x, Handle<BigInt> y);
35-
static Handle<BigInt> SignedRightShift(Handle<BigInt> x, Handle<BigInt> y);
34+
static MaybeHandle<BigInt> LeftShift(Handle<BigInt> x, Handle<BigInt> y);
35+
static MaybeHandle<BigInt> SignedRightShift(Handle<BigInt> x,
36+
Handle<BigInt> y);
3637
static MaybeHandle<BigInt> UnsignedRightShift(Handle<BigInt> x,
3738
Handle<BigInt> y);
3839
static bool LessThan(Handle<BigInt> x, Handle<BigInt> y);
@@ -146,6 +147,14 @@ class BigInt : public HeapObject {
146147
static Handle<BigInt> SpecialLeftShift(Handle<BigInt> x, int shift,
147148
SpecialLeftShiftMode mode);
148149

150+
// Specialized helpers for shift operations.
151+
static MaybeHandle<BigInt> LeftShiftByAbsolute(Handle<BigInt> x,
152+
Handle<BigInt> y);
153+
static Handle<BigInt> RightShiftByAbsolute(Handle<BigInt> x,
154+
Handle<BigInt> y);
155+
static Handle<BigInt> RightShiftByMaximum(Isolate* isolate, bool sign);
156+
static Maybe<digit_t> ToShiftAmount(Handle<BigInt> x);
157+
149158
static MaybeHandle<String> ToStringBasePowerOfTwo(Handle<BigInt> x,
150159
int radix);
151160

test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ bytecodes: [
428428
B(TestTypeOf), U8(5),
429429
B(JumpIfFalse), U8(4),
430430
B(Jump), U8(18),
431-
B(Wide), B(LdaSmi), I16(136),
431+
B(Wide), B(LdaSmi), I16(137),
432432
B(Star), R(18),
433433
B(LdaConstant), U8(16),
434434
B(Star), R(19),

test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ bytecodes: [
143143
B(TestTypeOf), U8(5),
144144
B(JumpIfFalse), U8(4),
145145
B(Jump), U8(18),
146-
B(Wide), B(LdaSmi), I16(136),
146+
B(Wide), B(LdaSmi), I16(137),
147147
B(Star), R(19),
148148
B(LdaConstant), U8(13),
149149
B(Star), R(20),
@@ -432,7 +432,7 @@ bytecodes: [
432432
B(TestTypeOf), U8(5),
433433
B(JumpIfFalse), U8(4),
434434
B(Jump), U8(18),
435-
B(Wide), B(LdaSmi), I16(136),
435+
B(Wide), B(LdaSmi), I16(137),
436436
B(Star), R(19),
437437
B(LdaConstant), U8(13),
438438
B(Star), R(20),
@@ -743,7 +743,7 @@ bytecodes: [
743743
B(TestTypeOf), U8(5),
744744
B(JumpIfFalse), U8(4),
745745
B(Jump), U8(18),
746-
B(Wide), B(LdaSmi), I16(136),
746+
B(Wide), B(LdaSmi), I16(137),
747747
B(Star), R(19),
748748
B(LdaConstant), U8(13),
749749
B(Star), R(20),
@@ -991,7 +991,7 @@ bytecodes: [
991991
B(TestTypeOf), U8(5),
992992
B(JumpIfFalse), U8(4),
993993
B(Jump), U8(18),
994-
B(Wide), B(LdaSmi), I16(136),
994+
B(Wide), B(LdaSmi), I16(137),
995995
B(Star), R(16),
996996
B(LdaConstant), U8(10),
997997
B(Star), R(17),

test/cctest/interpreter/bytecode_expectations/ForOf.golden

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ bytecodes: [
8686
B(TestTypeOf), U8(5),
8787
B(JumpIfFalse), U8(4),
8888
B(Jump), U8(18),
89-
B(Wide), B(LdaSmi), I16(136),
89+
B(Wide), B(LdaSmi), I16(137),
9090
B(Star), R(11),
9191
B(LdaConstant), U8(8),
9292
B(Star), R(12),
@@ -227,7 +227,7 @@ bytecodes: [
227227
B(TestTypeOf), U8(5),
228228
B(JumpIfFalse), U8(4),
229229
B(Jump), U8(18),
230-
B(Wide), B(LdaSmi), I16(136),
230+
B(Wide), B(LdaSmi), I16(137),
231231
B(Star), R(12),
232232
B(LdaConstant), U8(8),
233233
B(Star), R(13),
@@ -380,7 +380,7 @@ bytecodes: [
380380
B(TestTypeOf), U8(5),
381381
B(JumpIfFalse), U8(4),
382382
B(Jump), U8(18),
383-
B(Wide), B(LdaSmi), I16(136),
383+
B(Wide), B(LdaSmi), I16(137),
384384
B(Star), R(11),
385385
B(LdaConstant), U8(8),
386386
B(Star), R(12),
@@ -523,7 +523,7 @@ bytecodes: [
523523
B(TestTypeOf), U8(5),
524524
B(JumpIfFalse), U8(4),
525525
B(Jump), U8(18),
526-
B(Wide), B(LdaSmi), I16(136),
526+
B(Wide), B(LdaSmi), I16(137),
527527
B(Star), R(10),
528528
B(LdaConstant), U8(10),
529529
B(Star), R(11),

test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ bytecodes: [
9090
B(TestTypeOf), U8(5),
9191
B(JumpIfFalse), U8(4),
9292
B(Jump), U8(18),
93-
B(Wide), B(LdaSmi), I16(136),
93+
B(Wide), B(LdaSmi), I16(137),
9494
B(Star), R(13),
9595
B(LdaConstant), U8(7),
9696
B(Star), R(14),
@@ -268,7 +268,7 @@ bytecodes: [
268268
B(TestTypeOf), U8(5),
269269
B(JumpIfFalse), U8(4),
270270
B(Jump), U8(18),
271-
B(Wide), B(LdaSmi), I16(136),
271+
B(Wide), B(LdaSmi), I16(137),
272272
B(Star), R(13),
273273
B(LdaConstant), U8(11),
274274
B(Star), R(14),
@@ -422,7 +422,7 @@ bytecodes: [
422422
B(TestTypeOf), U8(5),
423423
B(JumpIfFalse), U8(4),
424424
B(Jump), U8(18),
425-
B(Wide), B(LdaSmi), I16(136),
425+
B(Wide), B(LdaSmi), I16(137),
426426
B(Star), R(11),
427427
B(LdaConstant), U8(9),
428428
B(Star), R(12),
@@ -524,7 +524,7 @@ bytecodes: [
524524
B(JumpIfUndefined), U8(6),
525525
B(Ldar), R(6),
526526
B(JumpIfNotNull), U8(16),
527-
B(LdaSmi), I8(65),
527+
B(LdaSmi), I8(66),
528528
B(Star), R(17),
529529
B(LdaConstant), U8(4),
530530
B(Star), R(18),
@@ -580,7 +580,7 @@ bytecodes: [
580580
B(TestTypeOf), U8(5),
581581
B(JumpIfFalse), U8(4),
582582
B(Jump), U8(18),
583-
B(Wide), B(LdaSmi), I16(136),
583+
B(Wide), B(LdaSmi), I16(137),
584584
B(Star), R(16),
585585
B(LdaConstant), U8(9),
586586
B(Star), R(17),
@@ -754,7 +754,7 @@ bytecodes: [
754754
B(TestTypeOf), U8(5),
755755
B(JumpIfFalse), U8(4),
756756
B(Jump), U8(18),
757-
B(Wide), B(LdaSmi), I16(136),
757+
B(Wide), B(LdaSmi), I16(137),
758758
B(Star), R(16),
759759
B(LdaConstant), U8(10),
760760
B(Star), R(17),
@@ -953,7 +953,7 @@ bytecodes: [
953953
B(TestTypeOf), U8(5),
954954
B(JumpIfFalse), U8(4),
955955
B(Jump), U8(18),
956-
B(Wide), B(LdaSmi), I16(136),
956+
B(Wide), B(LdaSmi), I16(137),
957957
B(Star), R(15),
958958
B(LdaConstant), U8(14),
959959
B(Star), R(16),
@@ -1116,7 +1116,7 @@ bytecodes: [
11161116
B(TestTypeOf), U8(5),
11171117
B(JumpIfFalse), U8(4),
11181118
B(Jump), U8(18),
1119-
B(Wide), B(LdaSmi), I16(136),
1119+
B(Wide), B(LdaSmi), I16(137),
11201120
B(Star), R(20),
11211121
B(LdaConstant), U8(7),
11221122
B(Star), R(21),
@@ -1358,7 +1358,7 @@ bytecodes: [
13581358
B(TestTypeOf), U8(5),
13591359
B(JumpIfFalse), U8(4),
13601360
B(Jump), U8(18),
1361-
B(Wide), B(LdaSmi), I16(136),
1361+
B(Wide), B(LdaSmi), I16(137),
13621362
B(Star), R(20),
13631363
B(LdaConstant), U8(9),
13641364
B(Star), R(21),

test/cctest/interpreter/bytecode_expectations/Generators.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ bytecodes: [
257257
B(TestTypeOf), U8(5),
258258
B(JumpIfFalse), U8(4),
259259
B(Jump), U8(18),
260-
B(Wide), B(LdaSmi), I16(136),
260+
B(Wide), B(LdaSmi), I16(137),
261261
B(Star), R(14),
262262
B(LdaConstant), U8(15),
263263
B(Star), R(15),

test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ bytecodes: [
231231
B(JumpIfUndefined), U8(6),
232232
B(Ldar), R(3),
233233
B(JumpIfNotNull), U8(16),
234-
B(LdaSmi), I8(65),
234+
B(LdaSmi), I8(66),
235235
B(Star), R(4),
236236
B(LdaConstant), U8(1),
237237
B(Star), R(5),

0 commit comments

Comments
 (0)