[bigint] Fix accidental input modification in Divide
"AbsoluteDivSmall" had a shortcut path for abs(divisor) == 1 where it would simply return the dividend as result. However, its caller "Divide" was blissfully ignorant of this trick and would therefore simply set the value's sign as needed, modifying the input. This CL prevents that, while continuing to avoid the full division algorithm for abs(divisor) == 1. Bug: v8:6791 Change-Id: I04cdc93f5ed2a696587c35c754e68f07012dd1a9 Reviewed-on: https://chromium-review.googlesource.com/772332 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#49433}
This commit is contained in:
parent
7e9448edbc
commit
b5997de8a9
@ -81,9 +81,14 @@ MaybeHandle<BigInt> BigInt::Divide(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
return x->GetIsolate()->factory()->NewBigIntFromInt(0);
|
||||
}
|
||||
Handle<BigInt> quotient;
|
||||
bool result_sign = x->sign() != y->sign();
|
||||
if (y->length() == 1) {
|
||||
digit_t divisor = y->digit(0);
|
||||
if (divisor == 1) {
|
||||
return result_sign == x->sign() ? x : UnaryMinus(x);
|
||||
}
|
||||
digit_t remainder;
|
||||
AbsoluteDivSmall(x, y->digit(0), "ient, &remainder);
|
||||
AbsoluteDivSmall(x, divisor, "ient, &remainder);
|
||||
} else {
|
||||
AbsoluteDivLarge(x, y, "ient, nullptr);
|
||||
}
|
||||
@ -93,22 +98,25 @@ MaybeHandle<BigInt> BigInt::Divide(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
}
|
||||
|
||||
MaybeHandle<BigInt> BigInt::Remainder(Handle<BigInt> x, Handle<BigInt> y) {
|
||||
Isolate* isolate = x->GetIsolate();
|
||||
// 1. If y is 0n, throw a RangeError exception.
|
||||
if (y->is_zero()) {
|
||||
THROW_NEW_ERROR(y->GetIsolate(),
|
||||
NewRangeError(MessageTemplate::kBigIntDivZero), BigInt);
|
||||
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntDivZero),
|
||||
BigInt);
|
||||
}
|
||||
// 2. Return the BigInt representing x modulo y.
|
||||
// See https://github.com/tc39/proposal-bigint/issues/84 though.
|
||||
if (AbsoluteCompare(x, y) < 0) return x;
|
||||
Handle<BigInt> remainder;
|
||||
if (y->length() == 1) {
|
||||
digit_t divisor = y->digit(0);
|
||||
if (divisor == 1) return isolate->factory()->NewBigIntFromInt(0);
|
||||
digit_t remainder_digit;
|
||||
AbsoluteDivSmall(x, y->digit(0), nullptr, &remainder_digit);
|
||||
AbsoluteDivSmall(x, divisor, nullptr, &remainder_digit);
|
||||
if (remainder_digit == 0) {
|
||||
return x->GetIsolate()->factory()->NewBigIntFromInt(0);
|
||||
return isolate->factory()->NewBigIntFromInt(0);
|
||||
}
|
||||
remainder = x->GetIsolate()->factory()->NewBigIntRaw(1);
|
||||
remainder = isolate->factory()->NewBigIntRaw(1);
|
||||
remainder->set_digit(0, remainder_digit);
|
||||
} else {
|
||||
AbsoluteDivLarge(x, y, nullptr, &remainder);
|
||||
@ -1035,11 +1043,6 @@ void BigInt::AbsoluteDivSmall(Handle<BigInt> x, digit_t divisor,
|
||||
DCHECK_NE(divisor, 0);
|
||||
DCHECK(!x->is_zero()); // Callers check anyway, no need to handle this.
|
||||
*remainder = 0;
|
||||
if (divisor == 1) {
|
||||
if (quotient != nullptr) *quotient = x;
|
||||
return;
|
||||
}
|
||||
|
||||
int length = x->length();
|
||||
if (quotient != nullptr) {
|
||||
if ((*quotient).is_null()) {
|
||||
|
18
test/mjsunit/harmony/bigint/regressions.js
Normal file
18
test/mjsunit/harmony/bigint/regressions.js
Normal file
@ -0,0 +1,18 @@
|
||||
// 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.
|
||||
|
||||
// Flags: --harmony-bigint --noopt
|
||||
|
||||
var a = 5n;
|
||||
var b = a / -1n;
|
||||
assertEquals(5n, a);
|
||||
assertEquals(-5n, b);
|
||||
assertEquals(5n, 5n / 1n);
|
||||
assertEquals(5n, -5n / -1n);
|
||||
assertEquals(-5n, -5n / 1n);
|
||||
|
||||
assertEquals(0n, 5n % 1n);
|
||||
assertEquals(0n, -5n % 1n);
|
||||
assertEquals(0n, 5n % -1n);
|
||||
assertEquals(0n, -5n % -1n);
|
Loading…
Reference in New Issue
Block a user