Commit 1eee4e1e authored by Nico Hartmann's avatar Nico Hartmann Committed by Commit Bot

Port BigInt addition to Torque

Implements the addition of BigInts as a Torque builtin, which performs necessary
checks and then calls into C++. The core logic of MutableBigInt::AbsoluteAdd,
MutableBigInt::AbsoluteSub and MutableBigInt::AbsoluteCompare is now used by both
the runtime and the Torque generated builtin for best performance.

Bug: v8:9213
Change-Id: I5f6af4dd226f11e6287bd04272ccae6ee5c26498
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1640211Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@google.com>
Cr-Commit-Position: refs/heads/master@{#62049}
parent e0f8c63b
...@@ -942,6 +942,7 @@ torque_files = [ ...@@ -942,6 +942,7 @@ torque_files = [
"src/builtins/array-unshift.tq", "src/builtins/array-unshift.tq",
"src/builtins/array.tq", "src/builtins/array.tq",
"src/builtins/base.tq", "src/builtins/base.tq",
"src/builtins/bigint.tq",
"src/builtins/boolean.tq", "src/builtins/boolean.tq",
"src/builtins/collections.tq", "src/builtins/collections.tq",
"src/builtins/data-view.tq", "src/builtins/data-view.tq",
...@@ -1469,6 +1470,7 @@ v8_source_set("v8_initializers") { ...@@ -1469,6 +1470,7 @@ v8_source_set("v8_initializers") {
"src/builtins/builtins-async-generator-gen.cc", "src/builtins/builtins-async-generator-gen.cc",
"src/builtins/builtins-async-iterator-gen.cc", "src/builtins/builtins-async-iterator-gen.cc",
"src/builtins/builtins-bigint-gen.cc", "src/builtins/builtins-bigint-gen.cc",
"src/builtins/builtins-bigint-gen.h",
"src/builtins/builtins-boolean-gen.cc", "src/builtins/builtins-boolean-gen.cc",
"src/builtins/builtins-call-gen.cc", "src/builtins/builtins-call-gen.cc",
"src/builtins/builtins-call-gen.h", "src/builtins/builtins-call-gen.h",
......
...@@ -86,7 +86,6 @@ extern class Oddball extends HeapObject { ...@@ -86,7 +86,6 @@ extern class Oddball extends HeapObject {
extern class HeapNumber extends HeapObject { value: float64; } extern class HeapNumber extends HeapObject { value: float64; }
type Number = Smi | HeapNumber; type Number = Smi | HeapNumber;
type BigInt extends HeapObject generates 'TNode<BigInt>';
type Numeric = Number | BigInt; type Numeric = Number | BigInt;
@abstract @abstract
...@@ -1038,6 +1037,10 @@ const kSymbolToString: constexpr MessageTemplate ...@@ -1038,6 +1037,10 @@ const kSymbolToString: constexpr MessageTemplate
generates 'MessageTemplate::kSymbolToString'; generates 'MessageTemplate::kSymbolToString';
const kPropertyNotFunction: constexpr MessageTemplate const kPropertyNotFunction: constexpr MessageTemplate
generates 'MessageTemplate::kPropertyNotFunction'; generates 'MessageTemplate::kPropertyNotFunction';
const kBigIntMaxLength: constexpr intptr
generates 'BigInt::kMaxLength';
const kBigIntTooBig: constexpr MessageTemplate
generates 'MessageTemplate::kBigIntTooBig';
const kMaxArrayIndex: const kMaxArrayIndex:
constexpr uint32 generates 'JSArray::kMaxArrayIndex'; constexpr uint32 generates 'JSArray::kMaxArrayIndex';
...@@ -1894,6 +1897,11 @@ Cast<HeapNumber>(o: HeapObject): HeapNumber ...@@ -1894,6 +1897,11 @@ Cast<HeapNumber>(o: HeapObject): HeapNumber
goto CastError; goto CastError;
} }
Cast<BigInt>(o: HeapObject): BigInt labels CastError {
if (IsBigInt(o)) return %RawDownCast<BigInt>(o);
goto CastError;
}
Cast<JSRegExp>(o: HeapObject): JSRegExp Cast<JSRegExp>(o: HeapObject): JSRegExp
labels CastError { labels CastError {
if (IsJSRegExp(o)) return %RawDownCast<JSRegExp>(o); if (IsJSRegExp(o)) return %RawDownCast<JSRegExp>(o);
...@@ -2183,6 +2191,9 @@ Convert<Number, int32>(i: int32): Number { ...@@ -2183,6 +2191,9 @@ Convert<Number, int32>(i: int32): Number {
Convert<intptr, int32>(i: int32): intptr { Convert<intptr, int32>(i: int32): intptr {
return ChangeInt32ToIntPtr(i); return ChangeInt32ToIntPtr(i);
} }
Convert<intptr, uint32>(i: uint32): intptr {
return Signed(ChangeUint32ToWord(i));
}
Convert<Smi, int32>(i: int32): Smi { Convert<Smi, int32>(i: int32): Smi {
return SmiFromInt32(i); return SmiFromInt32(i);
} }
...@@ -2750,6 +2761,7 @@ extern macro IsJSReceiver(HeapObject): bool; ...@@ -2750,6 +2761,7 @@ extern macro IsJSReceiver(HeapObject): bool;
extern macro TaggedIsCallable(Object): bool; extern macro TaggedIsCallable(Object): bool;
extern macro IsDetachedBuffer(JSArrayBuffer): bool; extern macro IsDetachedBuffer(JSArrayBuffer): bool;
extern macro IsHeapNumber(HeapObject): bool; extern macro IsHeapNumber(HeapObject): bool;
extern macro IsBigInt(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool; extern macro IsFixedArray(HeapObject): bool;
extern macro IsName(HeapObject): bool; extern macro IsName(HeapObject): bool;
extern macro IsPrivateSymbol(HeapObject): bool; extern macro IsPrivateSymbol(HeapObject): bool;
......
// Copyright 2019 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.
#include 'src/builtins/builtins-bigint-gen.h'
// TODO(nicohartmann): Discuss whether types used by multiple builtins should be
// in global namespace
@noVerifier
extern class BigIntBase extends HeapObject generates 'TNode<BigInt>' {
}
type BigInt extends BigIntBase;
@noVerifier
@hasSameInstanceTypeAsParent
extern class MutableBigInt extends BigIntBase generates 'TNode<BigInt>' {
}
Convert<BigInt, MutableBigInt>(i: MutableBigInt): BigInt {
assert(bigint::IsCanonicalized(i));
return %RawDownCast<BigInt>(Convert<BigIntBase>(i));
}
namespace bigint {
const kPositiveSign: uint32 = 0;
const kNegativeSign: uint32 = 1;
extern macro BigIntBuiltinsAssembler::CppAbsoluteAddAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize(
MutableBigInt, BigIntBase, BigIntBase): void;
extern macro BigIntBuiltinsAssembler::CppAbsoluteCompare(
BigIntBase, BigIntBase): int32;
extern macro BigIntBuiltinsAssembler::ReadBigIntSign(BigIntBase): uint32;
extern macro BigIntBuiltinsAssembler::ReadBigIntLength(BigIntBase): intptr;
extern macro BigIntBuiltinsAssembler::WriteBigIntSignAndLength(
MutableBigInt, uint32, intptr): void;
extern macro CodeStubAssembler::AllocateBigInt(intptr): MutableBigInt;
extern macro CodeStubAssembler::StoreBigIntDigit(
MutableBigInt, intptr, uintptr): void;
extern macro CodeStubAssembler::LoadBigIntDigit(BigIntBase, intptr): uintptr;
macro IsCanonicalized(bigint: BigIntBase): bool {
const length = ReadBigIntLength(bigint);
if (length == 0) {
return ReadBigIntSign(bigint) == kPositiveSign;
}
return LoadBigIntDigit(bigint, length - 1) != 0;
}
macro InvertSign(sign: uint32): uint32 {
return sign == kPositiveSign ? kNegativeSign : kPositiveSign;
}
macro WriteBigIntSign(bigint: MutableBigInt, sign: uint32): void {
WriteBigIntSignAndLength(bigint, sign, ReadBigIntLength(bigint));
}
macro AllocateEmptyBigInt(implicit context: Context)(
sign: uint32, length: intptr): MutableBigInt {
if (length > kBigIntMaxLength) {
ThrowRangeError(kBigIntTooBig);
}
let result: MutableBigInt = AllocateBigInt(length);
WriteBigIntSignAndLength(result, sign, length);
return result;
}
macro MutableBigIntAbsoluteCompare(x: BigIntBase, y: BigIntBase): int32 {
return CppAbsoluteCompare(x, y);
}
macro MutableBigIntAbsoluteSub(implicit context: Context)(
x: BigInt, y: BigInt, resultSign: uint32): BigInt {
const xlength = ReadBigIntLength(x);
const ylength = ReadBigIntLength(y);
const xsign = ReadBigIntSign(x);
assert(MutableBigIntAbsoluteCompare(x, y) >= 0);
if (xlength == 0) {
assert(ylength == 0);
return x;
}
if (ylength == 0) {
return resultSign == xsign ? x : BigIntUnaryMinus(x);
}
let result = AllocateEmptyBigInt(resultSign, xlength);
CppAbsoluteSubAndCanonicalize(result, x, y);
return Convert<BigInt>(result);
}
macro MutableBigIntAbsoluteAdd(implicit context: Context)(
xBigint: BigInt, yBigint: BigInt, resultSign: uint32): BigInt {
let xlength = ReadBigIntLength(xBigint);
let ylength = ReadBigIntLength(yBigint);
let x = xBigint;
let y = yBigint;
if (xlength < ylength) {
// Swap x and y so that x is longer.
x = yBigint;
y = xBigint;
const tempLength = xlength;
xlength = ylength;
ylength = tempLength;
}
// case: 0n + 0n
if (xlength == 0) {
assert(ylength == 0);
return x;
}
// case: x + 0n
if (ylength == 0) {
return resultSign == ReadBigIntSign(x) ? x : BigIntUnaryMinus(x);
}
// case: x + y
const result = AllocateEmptyBigInt(resultSign, xlength + 1);
CppAbsoluteAddAndCanonicalize(result, x, y);
return Convert<BigInt>(result);
}
builtin BigIntAdd(implicit context: Context)(xNum: Numeric, yNum: Numeric):
BigInt {
try {
const x = Cast<BigInt>(xNum) otherwise MixedTypes;
const y = Cast<BigInt>(yNum) otherwise MixedTypes;
const xsign = ReadBigIntSign(x);
const ysign = ReadBigIntSign(y);
if (xsign == ysign) {
// x + y == x + y
// -x + -y == -(x + y)
return MutableBigIntAbsoluteAdd(x, y, xsign);
}
// x + -y == x - y == -(y - x)
// -x + y == y - x == -(x - y)
if (MutableBigIntAbsoluteCompare(x, y) >= 0) {
return MutableBigIntAbsoluteSub(x, y, xsign);
}
return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign));
}
label MixedTypes {
ThrowTypeError(kBigIntMixedTypes);
}
}
builtin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt {
const length = ReadBigIntLength(bigint);
// There is no -0n.
if (length == 0) {
return bigint;
}
const result =
AllocateEmptyBigInt(InvertSign(ReadBigIntSign(bigint)), length);
for (let i: intptr = 0; i < length; ++i) {
StoreBigIntDigit(result, i, LoadBigIntDigit(bigint, i));
}
return Convert<BigInt>(result);
}
} // namespace bigint
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// 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.
#include "src/builtins/builtins-bigint-gen.h"
#include "src/builtins/builtins-utils-gen.h" #include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/codegen/code-stub-assembler.h" #include "src/codegen/code-stub-assembler.h"
......
// Copyright 2019 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.
#ifndef V8_BUILTINS_BUILTINS_BIGINT_GEN_H_
#define V8_BUILTINS_BUILTINS_BIGINT_GEN_H_
#include "src/codegen/code-stub-assembler.h"
#include "src/objects/bigint.h"
namespace v8 {
namespace internal {
class BigIntBuiltinsAssembler : public CodeStubAssembler {
public:
explicit BigIntBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
TNode<IntPtrT> ReadBigIntLength(TNode<BigInt> value) {
TNode<Word32T> bitfield = LoadBigIntBitfield(value);
return ChangeInt32ToIntPtr(
Signed(DecodeWord32<BigIntBase::LengthBits>(bitfield)));
}
TNode<Uint32T> ReadBigIntSign(TNode<BigInt> value) {
TNode<Word32T> bitfield = LoadBigIntBitfield(value);
return DecodeWord32<BigIntBase::SignBits>(bitfield);
}
void WriteBigIntSignAndLength(TNode<BigInt> bigint, TNode<Uint32T> sign,
TNode<IntPtrT> length) {
STATIC_ASSERT(BigIntBase::SignBits::kShift == 0);
TNode<Uint32T> bitfield = Unsigned(
Word32Or(Word32Shl(TruncateIntPtrToInt32(length),
Int32Constant(BigIntBase::LengthBits::kShift)),
Word32And(sign, Int32Constant(BigIntBase::SignBits::kMask))));
StoreBigIntBitfield(bigint, bitfield);
}
void CppAbsoluteAddAndCanonicalize(TNode<BigInt> result, TNode<BigInt> x,
TNode<BigInt> y) {
TNode<ExternalReference> mutable_big_int_absolute_add_and_canonicalize =
ExternalConstant(
ExternalReference::
mutable_big_int_absolute_add_and_canonicalize_function());
CallCFunction(mutable_big_int_absolute_add_and_canonicalize,
MachineType::AnyTagged(),
std::make_pair(MachineType::AnyTagged(), result),
std::make_pair(MachineType::AnyTagged(), x),
std::make_pair(MachineType::AnyTagged(), y));
}
void CppAbsoluteSubAndCanonicalize(TNode<BigInt> result, TNode<BigInt> x,
TNode<BigInt> y) {
TNode<ExternalReference> mutable_big_int_absolute_sub_and_canonicalize =
ExternalConstant(
ExternalReference::
mutable_big_int_absolute_sub_and_canonicalize_function());
CallCFunction(mutable_big_int_absolute_sub_and_canonicalize,
MachineType::AnyTagged(),
std::make_pair(MachineType::AnyTagged(), result),
std::make_pair(MachineType::AnyTagged(), x),
std::make_pair(MachineType::AnyTagged(), y));
}
TNode<Int32T> CppAbsoluteCompare(TNode<BigInt> x, TNode<BigInt> y) {
TNode<ExternalReference> mutable_big_int_absolute_compare =
ExternalConstant(
ExternalReference::mutable_big_int_absolute_compare_function());
TNode<Int32T> result = UncheckedCast<Int32T>(
CallCFunction(mutable_big_int_absolute_compare, MachineType::Int32(),
std::make_pair(MachineType::AnyTagged(), x),
std::make_pair(MachineType::AnyTagged(), y)));
return result;
}
};
} // namespace internal
} // namespace v8
#endif // V8_BUILTINS_BUILTINS_BIGINT_GEN_H_
...@@ -538,8 +538,8 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -538,8 +538,8 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&do_bigint_add); BIND(&do_bigint_add);
{ {
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(), TailCallBuiltin(Builtins::kBigIntAdd, context, var_left.value(),
var_right.value(), SmiConstant(Operation::kAdd))); var_right.value());
} }
BIND(&do_double_add); BIND(&do_double_add);
......
...@@ -212,74 +212,49 @@ namespace data_view { ...@@ -212,74 +212,49 @@ namespace data_view {
return Convert<Number>(result); return Convert<Number>(result);
} }
extern macro AllocateBigInt(intptr): BigInt;
extern macro StoreBigIntBitfield(BigInt, uint32): void;
extern macro StoreBigIntDigit(BigInt, constexpr int31, uintptr): void;
extern macro DataViewBuiltinsAssembler::DataViewEncodeBigIntBits(
constexpr bool, constexpr int31): uint32;
const kPositiveBigInt: constexpr bool = false;
const kNegativeBigInt: constexpr bool = true;
const kZeroDigitBigInt: constexpr int31 = 0; const kZeroDigitBigInt: constexpr int31 = 0;
const kOneDigitBigInt: constexpr int31 = 1; const kOneDigitBigInt: constexpr int31 = 1;
const kTwoDigitBigInt: constexpr int31 = 2; const kTwoDigitBigInt: constexpr int31 = 2;
macro CreateEmptyBigInt(isPositive: bool, length: constexpr int31): BigInt {
// Allocate a BigInt with the desired length (number of digits).
let result: BigInt = AllocateBigInt(length);
// Write the desired sign and length to the BigInt bitfield.
if (isPositive) {
StoreBigIntBitfield(
result, DataViewEncodeBigIntBits(kPositiveBigInt, length));
} else {
StoreBigIntBitfield(
result, DataViewEncodeBigIntBits(kNegativeBigInt, length));
}
return result;
}
// Create a BigInt on a 64-bit architecture from two 32-bit values. // Create a BigInt on a 64-bit architecture from two 32-bit values.
macro MakeBigIntOn64Bit( macro MakeBigIntOn64Bit(implicit context: Context)(
lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt {
// 0n is represented by a zero-length BigInt. // 0n is represented by a zero-length BigInt.
if (lowWord == 0 && highWord == 0) { if (lowWord == 0 && highWord == 0) {
return AllocateBigInt(kZeroDigitBigInt); return Convert<BigInt>(bigint::AllocateBigInt(kZeroDigitBigInt));
} }
let isPositive: bool = true; let sign: uint32 = bigint::kPositiveSign;
let highPart: intptr = Signed(Convert<uintptr>(highWord)); let highPart: intptr = Signed(Convert<uintptr>(highWord));
let lowPart: intptr = Signed(Convert<uintptr>(lowWord)); let lowPart: intptr = Signed(Convert<uintptr>(lowWord));
let rawValue: intptr = (highPart << 32) + lowPart; let rawValue: intptr = (highPart << 32) + lowPart;
if constexpr (signed) { if constexpr (signed) {
if (rawValue < 0) { if (rawValue < 0) {
isPositive = false; sign = bigint::kNegativeSign;
// We have to store the absolute value of rawValue in the digit. // We have to store the absolute value of rawValue in the digit.
rawValue = 0 - rawValue; rawValue = 0 - rawValue;
} }
} }
// Allocate the BigInt and store the absolute value. // Allocate the BigInt and store the absolute value.
let result: BigInt = CreateEmptyBigInt(isPositive, kOneDigitBigInt); let result: MutableBigInt =
bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt);
StoreBigIntDigit(result, 0, Unsigned(rawValue)); bigint::StoreBigIntDigit(result, 0, Unsigned(rawValue));
return Convert<BigInt>(result);
return result;
} }
// Create a BigInt on a 32-bit architecture from two 32-bit values. // Create a BigInt on a 32-bit architecture from two 32-bit values.
macro MakeBigIntOn32Bit( macro MakeBigIntOn32Bit(implicit context: Context)(
lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt {
// 0n is represented by a zero-length BigInt. // 0n is represented by a zero-length BigInt.
if (lowWord == 0 && highWord == 0) { if (lowWord == 0 && highWord == 0) {
return AllocateBigInt(kZeroDigitBigInt); return Convert<BigInt>(bigint::AllocateBigInt(kZeroDigitBigInt));
} }
// On a 32-bit platform, we might need 1 or 2 digits to store the number. // On a 32-bit platform, we might need 1 or 2 digits to store the number.
let needTwoDigits: bool = false; let needTwoDigits: bool = false;
let isPositive: bool = true; let sign: uint32 = bigint::kPositiveSign;
// We need to do some math on lowWord and highWord, // We need to do some math on lowWord and highWord,
// so Convert them to int32. // so Convert them to int32.
...@@ -293,7 +268,7 @@ namespace data_view { ...@@ -293,7 +268,7 @@ namespace data_view {
if constexpr (signed) { if constexpr (signed) {
// If highPart < 0, the number is always negative. // If highPart < 0, the number is always negative.
if (highPart < 0) { if (highPart < 0) {
isPositive = false; sign = bigint::kNegativeSign;
// We have to compute the absolute value by hand. // We have to compute the absolute value by hand.
// There will be a negative carry from the low word // There will be a negative carry from the low word
...@@ -322,25 +297,23 @@ namespace data_view { ...@@ -322,25 +297,23 @@ namespace data_view {
} }
// Allocate the BigInt with the right sign and length. // Allocate the BigInt with the right sign and length.
let result: BigInt; let result: MutableBigInt;
if (needTwoDigits) { if (needTwoDigits) {
result = CreateEmptyBigInt(isPositive, kTwoDigitBigInt); result = bigint::AllocateEmptyBigInt(sign, kTwoDigitBigInt);
} else { } else {
result = CreateEmptyBigInt(isPositive, kOneDigitBigInt); result = bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt);
} }
// Finally, write the digit(s) to the BigInt. // Finally, write the digit(s) to the BigInt.
StoreBigIntDigit(result, 0, Unsigned(Convert<intptr>(lowPart))); bigint::StoreBigIntDigit(result, 0, Unsigned(Convert<intptr>(lowPart)));
if (needTwoDigits) { if (needTwoDigits) {
StoreBigIntDigit(result, 1, Unsigned(Convert<intptr>(highPart))); bigint::StoreBigIntDigit(result, 1, Unsigned(Convert<intptr>(highPart)));
} }
return Convert<BigInt>(result);
return result;
} }
macro MakeBigInt(lowWord: uint32, highWord: uint32, signed: constexpr bool): macro MakeBigInt(implicit context: Context)(
BigInt { lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt {
// A BigInt digit has the platform word size, so we only need one digit // A BigInt digit has the platform word size, so we only need one digit
// on 64-bit platforms but may need two on 32-bit. // on 64-bit platforms but may need two on 32-bit.
if constexpr (Is64()) { if constexpr (Is64()) {
...@@ -350,7 +323,7 @@ namespace data_view { ...@@ -350,7 +323,7 @@ namespace data_view {
} }
} }
macro LoadDataViewBigInt( macro LoadDataViewBigInt(implicit context: Context)(
buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool,
signed: constexpr bool): BigInt { signed: constexpr bool): BigInt {
let dataPointer: RawPtr = buffer.backing_store; let dataPointer: RawPtr = buffer.backing_store;
...@@ -612,11 +585,10 @@ namespace data_view { ...@@ -612,11 +585,10 @@ namespace data_view {
} }
} }
extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntLength(BigInt): extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntLength(
uint32; BigIntBase): uint32;
extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntSign(BigInt): extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntSign(BigIntBase):
uint32; uint32;
extern macro LoadBigIntDigit(BigInt, constexpr int31): uintptr;
// We might get here a BigInt that is bigger than 64 bits, but we're only // We might get here a BigInt that is bigger than 64 bits, but we're only
// interested in the 64 lowest ones. This means the lowest BigInt digit // interested in the 64 lowest ones. This means the lowest BigInt digit
...@@ -636,13 +608,13 @@ namespace data_view { ...@@ -636,13 +608,13 @@ namespace data_view {
if (length != 0) { if (length != 0) {
if constexpr (Is64()) { if constexpr (Is64()) {
// There is always exactly 1 BigInt digit to load in this case. // There is always exactly 1 BigInt digit to load in this case.
let value: uintptr = LoadBigIntDigit(bigIntValue, 0); let value: uintptr = bigint::LoadBigIntDigit(bigIntValue, 0);
lowWord = Convert<uint32>(value); // Truncates value to 32 bits. lowWord = Convert<uint32>(value); // Truncates value to 32 bits.
highWord = Convert<uint32>(value >>> 32); highWord = Convert<uint32>(value >>> 32);
} else { // There might be either 1 or 2 BigInt digits we need to load. } else { // There might be either 1 or 2 BigInt digits we need to load.
lowWord = Convert<uint32>(LoadBigIntDigit(bigIntValue, 0)); lowWord = Convert<uint32>(bigint::LoadBigIntDigit(bigIntValue, 0));
if (length >= 2) { // Only load the second digit if there is one. if (length >= 2) { // Only load the second digit if there is one.
highWord = Convert<uint32>(LoadBigIntDigit(bigIntValue, 1)); highWord = Convert<uint32>(bigint::LoadBigIntDigit(bigIntValue, 1));
} }
} }
} }
......
...@@ -3128,14 +3128,10 @@ TNode<BigInt> CodeStubAssembler::AllocateBigInt(TNode<IntPtrT> length) { ...@@ -3128,14 +3128,10 @@ TNode<BigInt> CodeStubAssembler::AllocateBigInt(TNode<IntPtrT> length) {
} }
TNode<BigInt> CodeStubAssembler::AllocateRawBigInt(TNode<IntPtrT> length) { TNode<BigInt> CodeStubAssembler::AllocateRawBigInt(TNode<IntPtrT> length) {
// This is currently used only for 64-bit wide BigInts. If more general
// applicability is required, a large-object check must be added.
CSA_ASSERT(this, UintPtrLessThan(length, IntPtrConstant(3)));
TNode<IntPtrT> size = TNode<IntPtrT> size =
IntPtrAdd(IntPtrConstant(BigInt::kHeaderSize), IntPtrAdd(IntPtrConstant(BigInt::kHeaderSize),
Signed(WordShl(length, kSystemPointerSizeLog2))); Signed(WordShl(length, kSystemPointerSizeLog2)));
Node* raw_result = Allocate(size, kNone); Node* raw_result = Allocate(size, kAllowLargeObjectAllocation);
StoreMapNoWriteBarrier(raw_result, RootIndex::kBigIntMap); StoreMapNoWriteBarrier(raw_result, RootIndex::kBigIntMap);
if (FIELD_SIZE(BigInt::kOptionalPaddingOffset) != 0) { if (FIELD_SIZE(BigInt::kOptionalPaddingOffset) != 0) {
DCHECK_EQ(4, FIELD_SIZE(BigInt::kOptionalPaddingOffset)); DCHECK_EQ(4, FIELD_SIZE(BigInt::kOptionalPaddingOffset));
...@@ -3152,11 +3148,26 @@ void CodeStubAssembler::StoreBigIntBitfield(TNode<BigInt> bigint, ...@@ -3152,11 +3148,26 @@ void CodeStubAssembler::StoreBigIntBitfield(TNode<BigInt> bigint,
MachineRepresentation::kWord32); MachineRepresentation::kWord32);
} }
void CodeStubAssembler::StoreBigIntDigit(TNode<BigInt> bigint, int digit_index, void CodeStubAssembler::StoreBigIntDigit(TNode<BigInt> bigint,
intptr_t digit_index,
TNode<UintPtrT> digit) { TNode<UintPtrT> digit) {
CHECK_LE(0, digit_index);
CHECK_LT(digit_index, BigInt::kMaxLength);
StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(
bigint, BigInt::kDigitsOffset + digit_index * kSystemPointerSize, digit, bigint,
UintPtrT::kMachineRepresentation); BigInt::kDigitsOffset +
static_cast<int>(digit_index) * kSystemPointerSize,
digit, UintPtrT::kMachineRepresentation);
}
void CodeStubAssembler::StoreBigIntDigit(TNode<BigInt> bigint,
TNode<IntPtrT> digit_index,
TNode<UintPtrT> digit) {
TNode<IntPtrT> offset =
IntPtrAdd(IntPtrConstant(BigInt::kDigitsOffset),
IntPtrMul(digit_index, IntPtrConstant(kSystemPointerSize)));
StoreObjectFieldNoWriteBarrier(bigint, offset, digit,
UintPtrT::kMachineRepresentation);
} }
TNode<Word32T> CodeStubAssembler::LoadBigIntBitfield(TNode<BigInt> bigint) { TNode<Word32T> CodeStubAssembler::LoadBigIntBitfield(TNode<BigInt> bigint) {
...@@ -3165,10 +3176,23 @@ TNode<Word32T> CodeStubAssembler::LoadBigIntBitfield(TNode<BigInt> bigint) { ...@@ -3165,10 +3176,23 @@ TNode<Word32T> CodeStubAssembler::LoadBigIntBitfield(TNode<BigInt> bigint) {
} }
TNode<UintPtrT> CodeStubAssembler::LoadBigIntDigit(TNode<BigInt> bigint, TNode<UintPtrT> CodeStubAssembler::LoadBigIntDigit(TNode<BigInt> bigint,
int digit_index) { intptr_t digit_index) {
return UncheckedCast<UintPtrT>(LoadObjectField( CHECK_LE(0, digit_index);
bigint, BigInt::kDigitsOffset + digit_index * kSystemPointerSize, CHECK_LT(digit_index, BigInt::kMaxLength);
MachineType::UintPtr())); return UncheckedCast<UintPtrT>(
LoadObjectField(bigint,
BigInt::kDigitsOffset +
static_cast<int>(digit_index) * kSystemPointerSize,
MachineType::UintPtr()));
}
TNode<UintPtrT> CodeStubAssembler::LoadBigIntDigit(TNode<BigInt> bigint,
TNode<IntPtrT> digit_index) {
TNode<IntPtrT> offset =
IntPtrAdd(IntPtrConstant(BigInt::kDigitsOffset),
IntPtrMul(digit_index, IntPtrConstant(kSystemPointerSize)));
return UncheckedCast<UintPtrT>(
LoadObjectField(bigint, offset, MachineType::UintPtr()));
} }
TNode<ByteArray> CodeStubAssembler::AllocateByteArray(TNode<UintPtrT> length, TNode<ByteArray> CodeStubAssembler::AllocateByteArray(TNode<UintPtrT> length,
......
...@@ -1536,10 +1536,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -1536,10 +1536,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Like above, but allowing custom bitfield initialization. // Like above, but allowing custom bitfield initialization.
TNode<BigInt> AllocateRawBigInt(TNode<IntPtrT> length); TNode<BigInt> AllocateRawBigInt(TNode<IntPtrT> length);
void StoreBigIntBitfield(TNode<BigInt> bigint, TNode<Word32T> bitfield); void StoreBigIntBitfield(TNode<BigInt> bigint, TNode<Word32T> bitfield);
void StoreBigIntDigit(TNode<BigInt> bigint, int digit_index, void StoreBigIntDigit(TNode<BigInt> bigint, intptr_t digit_index,
TNode<UintPtrT> digit); TNode<UintPtrT> digit);
void StoreBigIntDigit(TNode<BigInt> bigint, TNode<IntPtrT> digit_index,
TNode<UintPtrT> digit);
TNode<Word32T> LoadBigIntBitfield(TNode<BigInt> bigint); TNode<Word32T> LoadBigIntBitfield(TNode<BigInt> bigint);
TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, int digit_index); TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, intptr_t digit_index);
TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint,
TNode<IntPtrT> digit_index);
// Allocate a ByteArray with the given length. // Allocate a ByteArray with the given length.
TNode<ByteArray> AllocateByteArray(TNode<UintPtrT> length, TNode<ByteArray> AllocateByteArray(TNode<UintPtrT> length,
......
...@@ -671,6 +671,15 @@ static Address LexicographicCompareWrapper(Isolate* isolate, Address smi_x, ...@@ -671,6 +671,15 @@ static Address LexicographicCompareWrapper(Isolate* isolate, Address smi_x,
FUNCTION_REFERENCE(smi_lexicographic_compare_function, FUNCTION_REFERENCE(smi_lexicographic_compare_function,
LexicographicCompareWrapper) LexicographicCompareWrapper)
FUNCTION_REFERENCE(mutable_big_int_absolute_add_and_canonicalize_function,
MutableBigInt_AbsoluteAddAndCanonicalize)
FUNCTION_REFERENCE(mutable_big_int_absolute_compare_function,
MutableBigInt_AbsoluteCompare)
FUNCTION_REFERENCE(mutable_big_int_absolute_sub_and_canonicalize_function,
MutableBigInt_AbsoluteSubAndCanonicalize)
FUNCTION_REFERENCE(check_object_type, CheckObjectType) FUNCTION_REFERENCE(check_object_type, CheckObjectType)
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
......
...@@ -149,6 +149,12 @@ class StatsCounter; ...@@ -149,6 +149,12 @@ class StatsCounter;
V(libc_memmove_function, "libc_memmove") \ V(libc_memmove_function, "libc_memmove") \
V(libc_memset_function, "libc_memset") \ V(libc_memset_function, "libc_memset") \
V(mod_two_doubles_operation, "mod_two_doubles") \ V(mod_two_doubles_operation, "mod_two_doubles") \
V(mutable_big_int_absolute_add_and_canonicalize_function, \
"MutableBigInt_AbsoluteAddAndCanonicalize") \
V(mutable_big_int_absolute_compare_function, \
"MutableBigInt_AbsoluteCompare") \
V(mutable_big_int_absolute_sub_and_canonicalize_function, \
"MutableBigInt_AbsoluteSubAndCanonicalize") \
V(new_deoptimizer_function, "Deoptimizer::New()") \ V(new_deoptimizer_function, "Deoptimizer::New()") \
V(orderedhashmap_gethash_raw, "orderedhashmap_gethash_raw") \ V(orderedhashmap_gethash_raw, "orderedhashmap_gethash_raw") \
V(printf_function, "printf") \ V(printf_function, "printf") \
......
...@@ -183,8 +183,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, ...@@ -183,8 +183,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&bigint); BIND(&bigint);
{ {
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt)); var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs, var_result.Bind(CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs));
SmiConstant(Operation::kAdd)));
Goto(&end); Goto(&end);
} }
...@@ -363,8 +362,12 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( ...@@ -363,8 +362,12 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
BIND(&if_bigint); BIND(&if_bigint);
{ {
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt)); var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs, if (op == Operation::kAdd) {
SmiConstant(op))); var_result.Bind(CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs));
} else {
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
SmiConstant(op)));
}
Goto(&end); Goto(&end);
} }
......
...@@ -46,6 +46,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt { ...@@ -46,6 +46,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
static MaybeHandle<BigInt> MakeImmutable(MaybeHandle<MutableBigInt> maybe); static MaybeHandle<BigInt> MakeImmutable(MaybeHandle<MutableBigInt> maybe);
static Handle<BigInt> MakeImmutable(Handle<MutableBigInt> result); static Handle<BigInt> MakeImmutable(Handle<MutableBigInt> result);
static void Canonicalize(MutableBigInt result);
// Allocation helpers. // Allocation helpers.
static MaybeHandle<MutableBigInt> New( static MaybeHandle<MutableBigInt> New(
Isolate* isolate, int length, Isolate* isolate, int length,
...@@ -64,6 +66,10 @@ class MutableBigInt : public FreshlyAllocatedBigInt { ...@@ -64,6 +66,10 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
SLOW_DCHECK(bigint->IsBigInt()); SLOW_DCHECK(bigint->IsBigInt());
return Handle<MutableBigInt>::cast(bigint); return Handle<MutableBigInt>::cast(bigint);
} }
static MutableBigInt cast(Object o) {
SLOW_DCHECK(o.IsBigInt());
return MutableBigInt(o.ptr());
}
static MutableBigInt unchecked_cast(Object o) { static MutableBigInt unchecked_cast(Object o) {
return MutableBigInt(o.ptr()); return MutableBigInt(o.ptr());
} }
...@@ -87,8 +93,13 @@ class MutableBigInt : public FreshlyAllocatedBigInt { ...@@ -87,8 +93,13 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
static MaybeHandle<BigInt> AbsoluteAdd(Isolate* isolate, Handle<BigInt> x, static MaybeHandle<BigInt> AbsoluteAdd(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y, bool result_sign); Handle<BigInt> y, bool result_sign);
static void AbsoluteAdd(MutableBigInt result, BigInt x, BigInt y);
static Handle<BigInt> AbsoluteSub(Isolate* isolate, Handle<BigInt> x, static Handle<BigInt> AbsoluteSub(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y, bool result_sign); Handle<BigInt> y, bool result_sign);
static void AbsoluteSub(MutableBigInt result, BigInt x, BigInt y);
static MaybeHandle<MutableBigInt> AbsoluteAddOne( static MaybeHandle<MutableBigInt> AbsoluteAddOne(
Isolate* isolate, Handle<BigIntBase> x, bool sign, Isolate* isolate, Handle<BigIntBase> x, bool sign,
MutableBigInt result_storage = MutableBigInt()); MutableBigInt result_storage = MutableBigInt());
...@@ -120,6 +131,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt { ...@@ -120,6 +131,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
static int AbsoluteCompare(Handle<BigIntBase> x, Handle<BigIntBase> y); static int AbsoluteCompare(Handle<BigIntBase> x, Handle<BigIntBase> y);
static int AbsoluteCompare(BigIntBase x, BigIntBase y);
static void MultiplyAccumulate(Handle<BigIntBase> multiplicand, static void MultiplyAccumulate(Handle<BigIntBase> multiplicand,
digit_t multiplier, digit_t multiplier,
Handle<MutableBigInt> accumulator, Handle<MutableBigInt> accumulator,
...@@ -347,32 +360,36 @@ MaybeHandle<BigInt> MutableBigInt::MakeImmutable( ...@@ -347,32 +360,36 @@ MaybeHandle<BigInt> MutableBigInt::MakeImmutable(
} }
Handle<BigInt> MutableBigInt::MakeImmutable(Handle<MutableBigInt> result) { Handle<BigInt> MutableBigInt::MakeImmutable(Handle<MutableBigInt> result) {
MutableBigInt::Canonicalize(*result);
return Handle<BigInt>::cast(result);
}
void MutableBigInt::Canonicalize(MutableBigInt result) {
// Check if we need to right-trim any leading zero-digits. // Check if we need to right-trim any leading zero-digits.
int old_length = result->length(); int old_length = result.length();
int new_length = old_length; int new_length = old_length;
while (new_length > 0 && result->digit(new_length - 1) == 0) new_length--; while (new_length > 0 && result.digit(new_length - 1) == 0) new_length--;
int to_trim = old_length - new_length; int to_trim = old_length - new_length;
if (to_trim != 0) { if (to_trim != 0) {
int size_delta = to_trim * kDigitSize; int size_delta = to_trim * MutableBigInt::kDigitSize;
Address new_end = result->address() + BigInt::SizeFor(new_length); Address new_end = result.address() + BigInt::SizeFor(new_length);
Heap* heap = result->GetHeap(); Heap* heap = result.GetHeap();
if (!heap->IsLargeObject(*result)) { if (!heap->IsLargeObject(result)) {
// We do not create a filler for objects in large object space. // We do not create a filler for objects in large object space.
// TODO(hpayer): We should shrink the large object page if the size // TODO(hpayer): We should shrink the large object page if the size
// of the object changed significantly. // of the object changed significantly.
heap->CreateFillerObjectAt(new_end, size_delta, ClearRecordedSlots::kNo); heap->CreateFillerObjectAt(new_end, size_delta, ClearRecordedSlots::kNo);
} }
result->synchronized_set_length(new_length); result.synchronized_set_length(new_length);
// Canonicalize -0n. // Canonicalize -0n.
if (new_length == 0) { if (new_length == 0) {
result->set_sign(false); result.set_sign(false);
// TODO(jkummerow): If we cache a canonical 0n, return that here. // TODO(jkummerow): If we cache a canonical 0n, return that here.
} }
} }
DCHECK_IMPLIES(result->length() > 0, DCHECK_IMPLIES(result.length() > 0,
result->digit(result->length() - 1) != 0); // MSD is non-zero. result.digit(result.length() - 1) != 0); // MSD is non-zero.
return Handle<BigInt>(result.location());
} }
Handle<BigInt> BigInt::Zero(Isolate* isolate) { Handle<BigInt> BigInt::Zero(Isolate* isolate) {
...@@ -1130,6 +1147,26 @@ void BigInt::BigIntShortPrint(std::ostream& os) { ...@@ -1130,6 +1147,26 @@ void BigInt::BigIntShortPrint(std::ostream& os) {
// Internal helpers. // Internal helpers.
void MutableBigInt::AbsoluteAdd(MutableBigInt result, BigInt x, BigInt y) {
DisallowHeapAllocation no_gc;
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);
}
MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate, MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate,
Handle<BigInt> x, Handle<BigInt> x,
Handle<BigInt> y, Handle<BigInt> y,
...@@ -1146,22 +1183,9 @@ MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate, ...@@ -1146,22 +1183,9 @@ MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate,
if (!New(isolate, x->length() + 1).ToHandle(&result)) { if (!New(isolate, x->length() + 1).ToHandle(&result)) {
return MaybeHandle<BigInt>(); return MaybeHandle<BigInt>();
} }
digit_t carry = 0;
int i = 0; AbsoluteAdd(*result, *x, *y);
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->set_sign(result_sign);
return MakeImmutable(result); return MakeImmutable(result);
} }
...@@ -1178,24 +1202,31 @@ Handle<BigInt> MutableBigInt::AbsoluteSub(Isolate* isolate, Handle<BigInt> x, ...@@ -1178,24 +1202,31 @@ Handle<BigInt> MutableBigInt::AbsoluteSub(Isolate* isolate, Handle<BigInt> x,
return result_sign == x->sign() ? x : BigInt::UnaryMinus(isolate, x); return result_sign == x->sign() ? x : BigInt::UnaryMinus(isolate, x);
} }
Handle<MutableBigInt> result = New(isolate, x->length()).ToHandleChecked(); Handle<MutableBigInt> result = New(isolate, x->length()).ToHandleChecked();
AbsoluteSub(*result, *x, *y);
result->set_sign(result_sign);
return MakeImmutable(result);
}
void MutableBigInt::AbsoluteSub(MutableBigInt result, BigInt x, BigInt y) {
DisallowHeapAllocation no_gc;
digit_t borrow = 0; digit_t borrow = 0;
int i = 0; int i = 0;
for (; i < y->length(); i++) { for (; i < y.length(); i++) {
digit_t new_borrow = 0; digit_t new_borrow = 0;
digit_t difference = digit_sub(x->digit(i), y->digit(i), &new_borrow); digit_t difference = digit_sub(x.digit(i), y.digit(i), &new_borrow);
difference = digit_sub(difference, borrow, &new_borrow); difference = digit_sub(difference, borrow, &new_borrow);
result->set_digit(i, difference); result.set_digit(i, difference);
borrow = new_borrow; borrow = new_borrow;
} }
for (; i < x->length(); i++) { for (; i < x.length(); i++) {
digit_t new_borrow = 0; digit_t new_borrow = 0;
digit_t difference = digit_sub(x->digit(i), borrow, &new_borrow); digit_t difference = digit_sub(x.digit(i), borrow, &new_borrow);
result->set_digit(i, difference); result.set_digit(i, difference);
borrow = new_borrow; borrow = new_borrow;
} }
DCHECK_EQ(0, borrow); DCHECK_EQ(0, borrow);
result->set_sign(result_sign);
return MakeImmutable(result);
} }
// Adds 1 to the absolute value of {x} and sets the result's sign to {sign}. // Adds 1 to the absolute value of {x} and sets the result's sign to {sign}.
...@@ -1375,12 +1406,17 @@ Handle<MutableBigInt> MutableBigInt::AbsoluteXor(Isolate* isolate, ...@@ -1375,12 +1406,17 @@ Handle<MutableBigInt> MutableBigInt::AbsoluteXor(Isolate* isolate,
// Returns a positive value if abs(x) > abs(y), a negative value if // Returns a positive value if abs(x) > abs(y), a negative value if
// abs(x) < abs(y), or zero if abs(x) == abs(y). // abs(x) < abs(y), or zero if abs(x) == abs(y).
int MutableBigInt::AbsoluteCompare(Handle<BigIntBase> x, Handle<BigIntBase> y) { int MutableBigInt::AbsoluteCompare(Handle<BigIntBase> x, Handle<BigIntBase> y) {
int diff = x->length() - y->length(); return MutableBigInt::AbsoluteCompare(*x, *y);
}
int MutableBigInt::AbsoluteCompare(BigIntBase x, BigIntBase y) {
DisallowHeapAllocation no_gc;
int diff = x.length() - y.length();
if (diff != 0) return diff; if (diff != 0) return diff;
int i = x->length() - 1; int i = x.length() - 1;
while (i >= 0 && x->digit(i) == y->digit(i)) i--; while (i >= 0 && x.digit(i) == y.digit(i)) i--;
if (i < 0) return 0; if (i < 0) return 0;
return x->digit(i) > y->digit(i) ? 1 : -1; return x.digit(i) > y.digit(i) ? 1 : -1;
} }
// Multiplies {multiplicand} with {multiplier} and adds the result to // Multiplies {multiplicand} with {multiplier} and adds the result to
...@@ -2674,5 +2710,32 @@ void BigInt::BigIntPrint(std::ostream& os) { ...@@ -2674,5 +2710,32 @@ void BigInt::BigIntPrint(std::ostream& os) {
} }
#endif // OBJECT_PRINT #endif // OBJECT_PRINT
void MutableBigInt_AbsoluteAddAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr) {
BigInt x = BigInt::cast(Object(x_addr));
BigInt y = BigInt::cast(Object(y_addr));
MutableBigInt result = MutableBigInt::cast(Object(result_addr));
MutableBigInt::AbsoluteAdd(result, x, y);
MutableBigInt::Canonicalize(result);
}
int32_t MutableBigInt_AbsoluteCompare(Address x_addr, Address y_addr) {
BigInt x = BigInt::cast(Object(x_addr));
BigInt y = BigInt::cast(Object(y_addr));
return MutableBigInt::AbsoluteCompare(x, y);
}
void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr) {
BigInt x = BigInt::cast(Object(x_addr));
BigInt y = BigInt::cast(Object(y_addr));
MutableBigInt result = MutableBigInt::cast(Object(result_addr));
MutableBigInt::AbsoluteSub(result, x, y);
MutableBigInt::Canonicalize(result);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void MutableBigInt_AbsoluteAddAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr);
int32_t MutableBigInt_AbsoluteCompare(Address x_addr, Address y_addr);
void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr,
Address x_addr, Address y_addr);
class BigInt; class BigInt;
class ValueDeserializer; class ValueDeserializer;
class ValueSerializer; class ValueSerializer;
......
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