Reland "[bigint] Begin src/bigint refactoring"

This is a reland of c4b44d5d48

Original change's description:
> [bigint] Begin src/bigint refactoring
>
> This patch moves a first function, Compare, from src/objects/bigint.cc
> to src/bigint/, to blaze the trail. More to follow!
>
> Bug: v8:11515
> Change-Id: Id7fa0b40ea852dbed1360f7ab439cb32d0c15762
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2737295
> Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
> Reviewed-by: Hannes Payer <hpayer@chromium.org>
> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73511}

Bug: v8:11515
Change-Id: I50a81593a8acaa91161bb01a445bddbb8e6315c4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2773804
Reviewed-by: Hannes Payer <hpayer@chromium.org>
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73610}
This commit is contained in:
Jakob Kummerow 2021-03-19 15:16:09 +01:00 committed by Commit Bot
parent bdcd7d79d3
commit 9790f26590
7 changed files with 199 additions and 27 deletions

View File

@ -4264,6 +4264,7 @@ v8_source_set("v8_base_without_compiler") {
deps = [
":torque_generated_definitions",
":v8_bigint",
":v8_cppgc_shared",
":v8_headers",
":v8_libbase",
@ -4780,6 +4781,15 @@ v8_source_set("fuzzer_support") {
]
}
v8_source_set("v8_bigint") {
sources = [
"src/bigint/bigint.h",
"src/bigint/vector-arithmetic.cc",
]
configs = [ ":internal_config" ]
}
v8_source_set("v8_cppgc_shared") {
sources = [
"src/heap/base/stack.cc",

View File

@ -6,6 +6,8 @@ include_rules = [
"-src/baseline",
"+src/baseline/baseline.h",
"+src/baseline/bytecode-offset-iterator.h",
"-src/bigint",
"+src/bigint/bigint.h",
"-src/compiler",
"+src/compiler/pipeline.h",
"+src/compiler/code-assembler.h",

13
src/bigint/DEPS Normal file
View File

@ -0,0 +1,13 @@
include_rules = [
# Don't depend on the rest of V8.
"-include",
"-src",
"+src/bigint",
]
specific_include_rules = {
# The public interface should not depend on internals.
"bigint.h": [
"-src/bigint",
],
}

2
src/bigint/OWNERS Normal file
View File

@ -0,0 +1,2 @@
jkummerow@chromium.org
thibaudm@chromium.org

130
src/bigint/bigint.h Normal file
View File

@ -0,0 +1,130 @@
// Copyright 2021 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_BIGINT_BIGINT_H_
#define V8_BIGINT_BIGINT_H_
#include <stdint.h>
#include <algorithm>
#include <iostream>
namespace v8 {
namespace bigint {
// To play nice with embedders' macros, we define our own DCHECK here.
// It's only used in this file, and undef'ed at the end.
#ifdef DEBUG
#define BIGINT_H_DCHECK(cond) \
if (!(cond)) { \
std::cerr << __FILE__ << ":" << __LINE__ << ": "; \
std::cerr << "Assertion failed: " #cond "\n"; \
abort(); \
}
#else
#define BIGINT_H_DCHECK(cond) (void(0))
#endif
// The type of a digit: a register-width unsigned integer.
using digit_t = uintptr_t;
using signed_digit_t = intptr_t;
#if UINTPTR_MAX == 0xFFFFFFFF
// 32-bit platform.
using twodigit_t = uint64_t;
#define HAVE_TWODIGIT_T 1
static constexpr int kLog2DigitBits = 5;
#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFF
// 64-bit platform.
static constexpr int kLog2DigitBits = 6;
#if defined(__SIZEOF_INT128__)
using twodigit_t = __uint128_t;
#define HAVE_TWODIGIT_T 1
#endif // defined(__SIZEOF_INT128__)
#else
#error Unsupported platform.
#endif
static constexpr int kDigitBits = 1 << kLog2DigitBits;
static_assert(kDigitBits == 8 * sizeof(digit_t), "inconsistent type sizes");
// Describes an array of digits, also known as a BigInt. Unsigned.
// Does not own the memory it points at, and only gives read-only access to it.
// Digits are stored in little-endian order.
class Digits {
public:
// This is the constructor intended for public consumption.
Digits(digit_t* mem, int len) : digits_(mem), len_(len) {
// Require 4-byte alignment (even on 64-bit platforms).
// TODO(jkummerow): See if we can tighten BigInt alignment in V8 to
// system pointer size, and raise this requirement to that.
BIGINT_H_DCHECK((reinterpret_cast<uintptr_t>(mem) & 3) == 0);
}
// Provides a "slice" view into another Digits object.
Digits(Digits src, int offset, int len)
: digits_(src.digits_ + offset),
len_(std::max(0, std::min(src.len_ - offset, len))) {
BIGINT_H_DCHECK(offset >= 0);
}
// Alternative way to get a "slice" view into another Digits object.
Digits operator+(int i) {
BIGINT_H_DCHECK(i >= 0 && i <= len_);
return Digits(digits_ + i, len_ - i);
}
// Provides access to individual digits.
digit_t operator[](int i) {
BIGINT_H_DCHECK(i >= 0 && i < len_);
return read_4byte_aligned(i);
}
// Convenience accessor for the most significant digit.
digit_t msd() {
BIGINT_H_DCHECK(len_ > 0);
return read_4byte_aligned(len_ - 1);
}
// Checks "pointer equality" (does not compare digits contents).
bool operator==(const Digits& other) const {
return digits_ == other.digits_ && len_ == other.len_;
}
// Decrements {len_} until there are no leading zero digits left.
void Normalize() {
while (len_ > 0 && msd() == 0) len_--;
}
// Unconditionally drops exactly one leading zero digit.
void TrimOne() {
BIGINT_H_DCHECK(len_ > 0 && msd() == 0);
len_--;
}
int len() { return len_; }
const digit_t* digits() const { return digits_; }
protected:
friend class TemporaryLeftShift;
digit_t* digits_;
int len_;
private:
// We require externally-provided digits arrays to be 4-byte aligned, but
// not necessarily 8-byte aligned; so on 64-bit platforms we use memcpy
// to allow unaligned reads.
digit_t read_4byte_aligned(int i) {
if (sizeof(digit_t) == 4) {
return digits_[i];
} else {
digit_t result;
memcpy(&result, digits_ + i, sizeof(result));
return result;
}
}
};
// Returns r such that r < 0 if A < B; r > 0 if A > B; r == 0 if A == B.
int Compare(Digits A, Digits B);
} // namespace bigint
} // namespace v8
#undef BIGINT_H_DCHECK
#endif // V8_BIGINT_BIGINT_H_

View File

@ -0,0 +1,22 @@
// Copyright 2021 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/bigint/bigint.h"
namespace v8 {
namespace bigint {
int Compare(Digits A, Digits B) {
A.Normalize();
B.Normalize();
int diff = A.len() - B.len();
if (diff != 0) return diff;
int i = A.len() - 1;
while (i >= 0 && A[i] == B[i]) i--;
if (i < 0) return 0;
return A[i] > B[i] ? 1 : -1;
}
} // namespace bigint
} // namespace v8

View File

@ -19,6 +19,7 @@
#include "src/objects/bigint.h"
#include "src/bigint/bigint.h"
#include "src/execution/isolate-inl.h"
#include "src/heap/factory.h"
#include "src/heap/heap-write-barrier-inl.h"
@ -135,10 +136,6 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
MutableBigInt result_storage = MutableBigInt());
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,
@ -232,6 +229,9 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
bool IsMutableBigInt() const { return IsBigInt(); }
static_assert(std::is_same<bigint::digit_t, BigIntBase::digit_t>::value,
"We must be able to call BigInt library functions");
NEVER_READ_ONLY_SPACE
OBJECT_CONSTRUCTORS(MutableBigInt, FreshlyAllocatedBigInt);
@ -243,6 +243,15 @@ NEVER_READ_ONLY_SPACE_IMPL(MutableBigInt)
#include "src/base/platform/wrappers.h"
#include "src/objects/object-macros-undef.h"
struct GetDigits : bigint::Digits {
explicit GetDigits(Handle<BigIntBase> bigint) : GetDigits(*bigint) {}
explicit GetDigits(BigIntBase bigint)
: bigint::Digits(
reinterpret_cast<bigint::digit_t*>(
bigint.ptr() + BigIntBase::kDigitsOffset - kHeapObjectTag),
bigint.length()) {}
};
template <typename T, typename Isolate>
MaybeHandle<T> ThrowBigIntTooBig(Isolate* isolate) {
// If the result of a BigInt computation is truncated to 64 bit, Turbofan
@ -560,7 +569,7 @@ MaybeHandle<BigInt> BigInt::Divide(Isolate* isolate, Handle<BigInt> x,
// 2. Let quotient be the mathematical value of x divided by y.
// 3. Return a BigInt representing quotient rounded towards 0 to the next
// integral value.
if (MutableBigInt::AbsoluteCompare(x, y) < 0) {
if (bigint::Compare(GetDigits(x), GetDigits(y)) < 0) {
return Zero(isolate);
}
Handle<MutableBigInt> quotient;
@ -590,7 +599,7 @@ MaybeHandle<BigInt> BigInt::Remainder(Isolate* isolate, Handle<BigInt> x,
}
// 2. Return the BigInt representing x modulo y.
// See https://github.com/tc39/proposal-bigint/issues/84 though.
if (MutableBigInt::AbsoluteCompare(x, y) < 0) return x;
if (bigint::Compare(GetDigits(x), GetDigits(y)) < 0) return x;
Handle<MutableBigInt> remainder;
if (y->length() == 1) {
digit_t divisor = y->digit(0);
@ -622,7 +631,7 @@ MaybeHandle<BigInt> BigInt::Add(Isolate* isolate, Handle<BigInt> x,
}
// x + -y == x - y == -(y - x)
// -x + y == y - x == -(x - y)
if (MutableBigInt::AbsoluteCompare(x, y) >= 0) {
if (bigint::Compare(GetDigits(x), GetDigits(y)) >= 0) {
return MutableBigInt::AbsoluteSub(isolate, x, y, xsign);
}
return MutableBigInt::AbsoluteSub(isolate, y, x, !xsign);
@ -638,7 +647,7 @@ MaybeHandle<BigInt> BigInt::Subtract(Isolate* isolate, Handle<BigInt> x,
}
// x - y == -(y - x)
// (-x) - (-y) == y - x == -(x - y)
if (MutableBigInt::AbsoluteCompare(x, y) >= 0) {
if (bigint::Compare(GetDigits(x), GetDigits(y)) >= 0) {
return MutableBigInt::AbsoluteSub(isolate, x, y, xsign);
}
return MutableBigInt::AbsoluteSub(isolate, y, x, !xsign);
@ -691,7 +700,7 @@ ComparisonResult BigInt::CompareToBigInt(Handle<BigInt> x, Handle<BigInt> y) {
bool x_sign = x->sign();
if (x_sign != y->sign()) return UnequalSign(x_sign);
int result = MutableBigInt::AbsoluteCompare(x, y);
int result = bigint::Compare(GetDigits(x), GetDigits(y));
if (result > 0) return AbsoluteGreater(x_sign);
if (result < 0) return AbsoluteLess(x_sign);
return ComparisonResult::kEqual;
@ -1230,7 +1239,7 @@ MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate,
Handle<BigInt> MutableBigInt::AbsoluteSub(Isolate* isolate, Handle<BigInt> x,
Handle<BigInt> y, bool result_sign) {
DCHECK(x->length() >= y->length());
SLOW_DCHECK(AbsoluteCompare(x, y) >= 0);
SLOW_DCHECK(bigint::Compare(GetDigits(x), GetDigits(y)) >= 0);
if (x->is_zero()) {
DCHECK(y->is_zero());
return x;
@ -1440,22 +1449,6 @@ Handle<MutableBigInt> MutableBigInt::AbsoluteXor(Isolate* isolate,
[](digit_t a, digit_t b) { return a ^ b; });
}
// 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) {
return MutableBigInt::AbsoluteCompare(*x, *y);
}
int MutableBigInt::AbsoluteCompare(BigIntBase x, BigIntBase y) {
DisallowGarbageCollection 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--;
if (i < 0) return 0;
return x.digit(i) > y.digit(i) ? 1 : -1;
}
// Multiplies {multiplicand} with {multiplier} and adds the result to
// {accumulator}, starting at {accumulator_index} for the least-significant
// digit.
@ -2766,7 +2759,7 @@ 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);
return bigint::Compare(GetDigits(x), GetDigits(y));
}
void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr,