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/+/1640211
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@google.com>
Cr-Commit-Position: refs/heads/master@{#62049}
This commit is contained in:
Nico Hartmann 2019-06-06 11:38:51 +02:00 committed by Commit Bot
parent e0f8c63b65
commit 1eee4e1ee5
14 changed files with 474 additions and 115 deletions

View File

@ -942,6 +942,7 @@ torque_files = [
"src/builtins/array-unshift.tq",
"src/builtins/array.tq",
"src/builtins/base.tq",
"src/builtins/bigint.tq",
"src/builtins/boolean.tq",
"src/builtins/collections.tq",
"src/builtins/data-view.tq",
@ -1469,6 +1470,7 @@ v8_source_set("v8_initializers") {
"src/builtins/builtins-async-generator-gen.cc",
"src/builtins/builtins-async-iterator-gen.cc",
"src/builtins/builtins-bigint-gen.cc",
"src/builtins/builtins-bigint-gen.h",
"src/builtins/builtins-boolean-gen.cc",
"src/builtins/builtins-call-gen.cc",
"src/builtins/builtins-call-gen.h",

View File

@ -86,7 +86,6 @@ extern class Oddball extends HeapObject {
extern class HeapNumber extends HeapObject { value: float64; }
type Number = Smi | HeapNumber;
type BigInt extends HeapObject generates 'TNode<BigInt>';
type Numeric = Number | BigInt;
@abstract
@ -1038,6 +1037,10 @@ const kSymbolToString: constexpr MessageTemplate
generates 'MessageTemplate::kSymbolToString';
const kPropertyNotFunction: constexpr MessageTemplate
generates 'MessageTemplate::kPropertyNotFunction';
const kBigIntMaxLength: constexpr intptr
generates 'BigInt::kMaxLength';
const kBigIntTooBig: constexpr MessageTemplate
generates 'MessageTemplate::kBigIntTooBig';
const kMaxArrayIndex:
constexpr uint32 generates 'JSArray::kMaxArrayIndex';
@ -1894,6 +1897,11 @@ Cast<HeapNumber>(o: HeapObject): HeapNumber
goto CastError;
}
Cast<BigInt>(o: HeapObject): BigInt labels CastError {
if (IsBigInt(o)) return %RawDownCast<BigInt>(o);
goto CastError;
}
Cast<JSRegExp>(o: HeapObject): JSRegExp
labels CastError {
if (IsJSRegExp(o)) return %RawDownCast<JSRegExp>(o);
@ -2183,6 +2191,9 @@ Convert<Number, int32>(i: int32): Number {
Convert<intptr, int32>(i: int32): intptr {
return ChangeInt32ToIntPtr(i);
}
Convert<intptr, uint32>(i: uint32): intptr {
return Signed(ChangeUint32ToWord(i));
}
Convert<Smi, int32>(i: int32): Smi {
return SmiFromInt32(i);
}
@ -2750,6 +2761,7 @@ extern macro IsJSReceiver(HeapObject): bool;
extern macro TaggedIsCallable(Object): bool;
extern macro IsDetachedBuffer(JSArrayBuffer): bool;
extern macro IsHeapNumber(HeapObject): bool;
extern macro IsBigInt(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool;
extern macro IsName(HeapObject): bool;
extern macro IsPrivateSymbol(HeapObject): bool;

176
src/builtins/bigint.tq Normal file
View File

@ -0,0 +1,176 @@
// 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

View File

@ -2,6 +2,7 @@
// 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"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/codegen/code-stub-assembler.h"

View File

@ -0,0 +1,80 @@
// 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_

View File

@ -538,8 +538,8 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&do_bigint_add);
{
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
var_right.value(), SmiConstant(Operation::kAdd)));
TailCallBuiltin(Builtins::kBigIntAdd, context, var_left.value(),
var_right.value());
}
BIND(&do_double_add);

View File

@ -212,74 +212,49 @@ namespace data_view {
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 kOneDigitBigInt: constexpr int31 = 1;
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.
macro MakeBigIntOn64Bit(
macro MakeBigIntOn64Bit(implicit context: Context)(
lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt {
// 0n is represented by a zero-length BigInt.
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 lowPart: intptr = Signed(Convert<uintptr>(lowWord));
let rawValue: intptr = (highPart << 32) + lowPart;
if constexpr (signed) {
if (rawValue < 0) {
isPositive = false;
sign = bigint::kNegativeSign;
// We have to store the absolute value of rawValue in the digit.
rawValue = 0 - rawValue;
}
}
// Allocate the BigInt and store the absolute value.
let result: BigInt = CreateEmptyBigInt(isPositive, kOneDigitBigInt);
StoreBigIntDigit(result, 0, Unsigned(rawValue));
return result;
let result: MutableBigInt =
bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt);
bigint::StoreBigIntDigit(result, 0, Unsigned(rawValue));
return Convert<BigInt>(result);
}
// 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 {
// 0n is represented by a zero-length BigInt.
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.
let needTwoDigits: bool = false;
let isPositive: bool = true;
let sign: uint32 = bigint::kPositiveSign;
// We need to do some math on lowWord and highWord,
// so Convert them to int32.
@ -293,7 +268,7 @@ namespace data_view {
if constexpr (signed) {
// If highPart < 0, the number is always negative.
if (highPart < 0) {
isPositive = false;
sign = bigint::kNegativeSign;
// We have to compute the absolute value by hand.
// There will be a negative carry from the low word
@ -322,25 +297,23 @@ namespace data_view {
}
// Allocate the BigInt with the right sign and length.
let result: BigInt;
let result: MutableBigInt;
if (needTwoDigits) {
result = CreateEmptyBigInt(isPositive, kTwoDigitBigInt);
result = bigint::AllocateEmptyBigInt(sign, kTwoDigitBigInt);
} else {
result = CreateEmptyBigInt(isPositive, kOneDigitBigInt);
result = bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt);
}
// 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) {
StoreBigIntDigit(result, 1, Unsigned(Convert<intptr>(highPart)));
bigint::StoreBigIntDigit(result, 1, Unsigned(Convert<intptr>(highPart)));
}
return result;
return Convert<BigInt>(result);
}
macro MakeBigInt(lowWord: uint32, highWord: uint32, signed: constexpr bool):
BigInt {
macro MakeBigInt(implicit context: Context)(
lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt {
// 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.
if constexpr (Is64()) {
@ -350,7 +323,7 @@ namespace data_view {
}
}
macro LoadDataViewBigInt(
macro LoadDataViewBigInt(implicit context: Context)(
buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool,
signed: constexpr bool): BigInt {
let dataPointer: RawPtr = buffer.backing_store;
@ -612,11 +585,10 @@ namespace data_view {
}
}
extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntLength(BigInt):
extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntLength(
BigIntBase): uint32;
extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntSign(BigIntBase):
uint32;
extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntSign(BigInt):
uint32;
extern macro LoadBigIntDigit(BigInt, constexpr int31): uintptr;
// 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
@ -636,13 +608,13 @@ namespace data_view {
if (length != 0) {
if constexpr (Is64()) {
// 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.
highWord = Convert<uint32>(value >>> 32);
} 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.
highWord = Convert<uint32>(LoadBigIntDigit(bigIntValue, 1));
highWord = Convert<uint32>(bigint::LoadBigIntDigit(bigIntValue, 1));
}
}
}

View File

@ -3128,14 +3128,10 @@ TNode<BigInt> CodeStubAssembler::AllocateBigInt(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 =
IntPtrAdd(IntPtrConstant(BigInt::kHeaderSize),
Signed(WordShl(length, kSystemPointerSizeLog2)));
Node* raw_result = Allocate(size, kNone);
Node* raw_result = Allocate(size, kAllowLargeObjectAllocation);
StoreMapNoWriteBarrier(raw_result, RootIndex::kBigIntMap);
if (FIELD_SIZE(BigInt::kOptionalPaddingOffset) != 0) {
DCHECK_EQ(4, FIELD_SIZE(BigInt::kOptionalPaddingOffset));
@ -3152,11 +3148,26 @@ void CodeStubAssembler::StoreBigIntBitfield(TNode<BigInt> bigint,
MachineRepresentation::kWord32);
}
void CodeStubAssembler::StoreBigIntDigit(TNode<BigInt> bigint, int digit_index,
void CodeStubAssembler::StoreBigIntDigit(TNode<BigInt> bigint,
intptr_t digit_index,
TNode<UintPtrT> digit) {
CHECK_LE(0, digit_index);
CHECK_LT(digit_index, BigInt::kMaxLength);
StoreObjectFieldNoWriteBarrier(
bigint, BigInt::kDigitsOffset + digit_index * kSystemPointerSize, digit,
UintPtrT::kMachineRepresentation);
bigint,
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) {
@ -3165,10 +3176,23 @@ TNode<Word32T> CodeStubAssembler::LoadBigIntBitfield(TNode<BigInt> bigint) {
}
TNode<UintPtrT> CodeStubAssembler::LoadBigIntDigit(TNode<BigInt> bigint,
int digit_index) {
return UncheckedCast<UintPtrT>(LoadObjectField(
bigint, BigInt::kDigitsOffset + digit_index * kSystemPointerSize,
MachineType::UintPtr()));
intptr_t digit_index) {
CHECK_LE(0, digit_index);
CHECK_LT(digit_index, BigInt::kMaxLength);
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,

View File

@ -1536,10 +1536,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Like above, but allowing custom bitfield initialization.
TNode<BigInt> AllocateRawBigInt(TNode<IntPtrT> length);
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);
void StoreBigIntDigit(TNode<BigInt> bigint, TNode<IntPtrT> digit_index,
TNode<UintPtrT> digit);
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.
TNode<ByteArray> AllocateByteArray(TNode<UintPtrT> length,

View File

@ -671,6 +671,15 @@ static Address LexicographicCompareWrapper(Isolate* isolate, Address smi_x,
FUNCTION_REFERENCE(smi_lexicographic_compare_function,
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)
#ifdef V8_INTL_SUPPORT

View File

@ -149,6 +149,12 @@ class StatsCounter;
V(libc_memmove_function, "libc_memmove") \
V(libc_memset_function, "libc_memset") \
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(orderedhashmap_gethash_raw, "orderedhashmap_gethash_raw") \
V(printf_function, "printf") \

View File

@ -183,8 +183,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&bigint);
{
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
SmiConstant(Operation::kAdd)));
var_result.Bind(CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs));
Goto(&end);
}
@ -363,8 +362,12 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
BIND(&if_bigint);
{
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
SmiConstant(op)));
if (op == Operation::kAdd) {
var_result.Bind(CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs));
} else {
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
SmiConstant(op)));
}
Goto(&end);
}

View File

@ -46,6 +46,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
static MaybeHandle<BigInt> MakeImmutable(MaybeHandle<MutableBigInt> maybe);
static Handle<BigInt> MakeImmutable(Handle<MutableBigInt> result);
static void Canonicalize(MutableBigInt result);
// Allocation helpers.
static MaybeHandle<MutableBigInt> New(
Isolate* isolate, int length,
@ -64,6 +66,10 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
SLOW_DCHECK(bigint->IsBigInt());
return Handle<MutableBigInt>::cast(bigint);
}
static MutableBigInt cast(Object o) {
SLOW_DCHECK(o.IsBigInt());
return MutableBigInt(o.ptr());
}
static MutableBigInt unchecked_cast(Object o) {
return MutableBigInt(o.ptr());
}
@ -87,8 +93,13 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
static MaybeHandle<BigInt> AbsoluteAdd(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y, bool result_sign);
static void AbsoluteAdd(MutableBigInt result, BigInt x, BigInt y);
static Handle<BigInt> AbsoluteSub(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y, bool result_sign);
static void AbsoluteSub(MutableBigInt result, BigInt x, BigInt y);
static MaybeHandle<MutableBigInt> AbsoluteAddOne(
Isolate* isolate, Handle<BigIntBase> x, bool sign,
MutableBigInt result_storage = MutableBigInt());
@ -120,6 +131,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
static int AbsoluteCompare(Handle<BigIntBase> x, Handle<BigIntBase> y);
static int AbsoluteCompare(BigIntBase x, BigIntBase y);
static void MultiplyAccumulate(Handle<BigIntBase> multiplicand,
digit_t multiplier,
Handle<MutableBigInt> accumulator,
@ -347,32 +360,36 @@ MaybeHandle<BigInt> MutableBigInt::MakeImmutable(
}
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.
int old_length = result->length();
int old_length = result.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;
if (to_trim != 0) {
int size_delta = to_trim * kDigitSize;
Address new_end = result->address() + BigInt::SizeFor(new_length);
Heap* heap = result->GetHeap();
if (!heap->IsLargeObject(*result)) {
int size_delta = to_trim * MutableBigInt::kDigitSize;
Address new_end = result.address() + BigInt::SizeFor(new_length);
Heap* heap = result.GetHeap();
if (!heap->IsLargeObject(result)) {
// We do not create a filler for objects in large object space.
// TODO(hpayer): We should shrink the large object page if the size
// of the object changed significantly.
heap->CreateFillerObjectAt(new_end, size_delta, ClearRecordedSlots::kNo);
}
result->synchronized_set_length(new_length);
result.synchronized_set_length(new_length);
// Canonicalize -0n.
if (new_length == 0) {
result->set_sign(false);
result.set_sign(false);
// TODO(jkummerow): If we cache a canonical 0n, return that here.
}
}
DCHECK_IMPLIES(result->length() > 0,
result->digit(result->length() - 1) != 0); // MSD is non-zero.
return Handle<BigInt>(result.location());
DCHECK_IMPLIES(result.length() > 0,
result.digit(result.length() - 1) != 0); // MSD is non-zero.
}
Handle<BigInt> BigInt::Zero(Isolate* isolate) {
@ -1130,6 +1147,26 @@ void BigInt::BigIntShortPrint(std::ostream& os) {
// 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,
Handle<BigInt> x,
Handle<BigInt> y,
@ -1146,22 +1183,9 @@ MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate,
if (!New(isolate, x->length() + 1).ToHandle(&result)) {
return MaybeHandle<BigInt>();
}
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);
AbsoluteAdd(*result, *x, *y);
result->set_sign(result_sign);
return MakeImmutable(result);
}
@ -1178,24 +1202,31 @@ Handle<BigInt> MutableBigInt::AbsoluteSub(Isolate* isolate, Handle<BigInt> x,
return result_sign == x->sign() ? x : BigInt::UnaryMinus(isolate, x);
}
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;
int i = 0;
for (; i < y->length(); i++) {
for (; i < y.length(); i++) {
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);
result->set_digit(i, difference);
result.set_digit(i, difference);
borrow = new_borrow;
}
for (; i < x->length(); i++) {
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);
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);
return MakeImmutable(result);
}
// 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,
// Returns a positive value if abs(x) > abs(y), a negative value if
// abs(x) < abs(y), or zero if abs(x) == abs(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;
int i = x->length() - 1;
while (i >= 0 && x->digit(i) == y->digit(i)) i--;
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;
return x.digit(i) > y.digit(i) ? 1 : -1;
}
// Multiplies {multiplicand} with {multiplier} and adds the result to
@ -2674,5 +2710,32 @@ void BigInt::BigIntPrint(std::ostream& os) {
}
#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 v8

View File

@ -16,6 +16,12 @@
namespace v8 {
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 ValueDeserializer;
class ValueSerializer;