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:
parent
e0f8c63b65
commit
1eee4e1ee5
2
BUILD.gn
2
BUILD.gn
@ -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",
|
||||
|
@ -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
176
src/builtins/bigint.tq
Normal 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
|
@ -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"
|
||||
|
80
src/builtins/builtins-bigint-gen.h
Normal file
80
src/builtins/builtins-bigint-gen.h
Normal 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_
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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") \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user