mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
deps: cherry-pick 477df06 from upstream v8
Original commit message:
[API] Expand BigInt API
Provide a more complete BigInt API.
Bug: v8:7712
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: Ic8562d616f3125deabdf8b52c7019b191bef0e07
Reviewed-on: chromium-review.googlesource.com/1101198
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54122}
PR-URL: https://github.com/nodejs/node/pull/21644
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
1 parent
eea5aeea47
commit
a921aff334
8 files changed
+271
-1
No files matched your search
+1
-1
@@ -28,7 +28,7 @@
|
||||
|
||||
# Reset this number to 0 on major V8 upgrades.
|
||||
# Increment by one for each non-official patch applied to deps/v8.
|
||||
'v8_embedder_string': '-node.6',
|
||||
'v8_embedder_string': '-node.7',
|
||||
|
||||
# Enable disassembler for `--print-code` v8 options
|
||||
'v8_enable_disassembler': 1,
|
||||
|
||||
Vendored
+42
@@ -3165,6 +3165,48 @@ class V8_EXPORT Uint32 : public Integer {
|
||||
class V8_EXPORT BigInt : public Primitive {
|
||||
public:
|
||||
static Local<BigInt> New(Isolate* isolate, int64_t value);
|
||||
static Local<BigInt> NewFromUnsigned(Isolate* isolate, uint64_t value);
|
||||
/**
|
||||
* Creates a new BigInt object using a specified sign bit and a
|
||||
* specified list of digits/words.
|
||||
* The resulting number is calculated as:
|
||||
*
|
||||
* (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...)
|
||||
*/
|
||||
static MaybeLocal<BigInt> NewFromWords(Local<Context> context, int sign_bit,
|
||||
int word_count, const uint64_t* words);
|
||||
|
||||
/**
|
||||
* Returns the value of this BigInt as an unsigned 64-bit integer.
|
||||
* If `lossless` is provided, it will reflect whether the return value was
|
||||
* truncated or wrapped around. In particular, it is set to `false` if this
|
||||
* BigInt is negative.
|
||||
*/
|
||||
uint64_t Uint64Value(bool* lossless = nullptr) const;
|
||||
|
||||
/**
|
||||
* Returns the value of this BigInt as a signed 64-bit integer.
|
||||
* If `lossless` is provided, it will reflect whether this BigInt was
|
||||
* truncated or not.
|
||||
*/
|
||||
int64_t Int64Value(bool* lossless = nullptr) const;
|
||||
|
||||
/**
|
||||
* Returns the number of 64-bit words needed to store the result of
|
||||
* ToWordsArray().
|
||||
*/
|
||||
int WordCount() const;
|
||||
|
||||
/**
|
||||
* Writes the contents of this BigInt to a specified memory location.
|
||||
* `sign_bit` must be provided and will be set to 1 if this BigInt is
|
||||
* negative.
|
||||
* `*word_count` has to be initialized to the length of the `words` array.
|
||||
* Upon return, it will be set to the actual number of words that would
|
||||
* be needed to store this BigInt (i.e. the return value of `WordCount()`).
|
||||
*/
|
||||
void ToWordsArray(int* sign_bit, int* word_count, uint64_t* words) const;
|
||||
|
||||
V8_INLINE static BigInt* Cast(v8::Value* obj);
|
||||
|
||||
private:
|
||||
|
||||
Vendored
+43
@@ -8000,6 +8000,49 @@ Local<BigInt> v8::BigInt::New(Isolate* isolate, int64_t value) {
|
||||
return Utils::ToLocal(result);
|
||||
}
|
||||
|
||||
Local<BigInt> v8::BigInt::NewFromUnsigned(Isolate* isolate, uint64_t value) {
|
||||
CHECK(i::FLAG_harmony_bigint);
|
||||
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(internal_isolate);
|
||||
i::Handle<i::BigInt> result = i::BigInt::FromUint64(internal_isolate, value);
|
||||
return Utils::ToLocal(result);
|
||||
}
|
||||
|
||||
MaybeLocal<BigInt> v8::BigInt::NewFromWords(Local<Context> context,
|
||||
int sign_bit, int word_count,
|
||||
const uint64_t* words) {
|
||||
CHECK(i::FLAG_harmony_bigint);
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
|
||||
ENTER_V8_NO_SCRIPT(isolate, context, BigInt, NewFromWords,
|
||||
MaybeLocal<BigInt>(), InternalEscapableScope);
|
||||
i::MaybeHandle<i::BigInt> result =
|
||||
i::BigInt::FromWords64(isolate, sign_bit, word_count, words);
|
||||
has_pending_exception = result.is_null();
|
||||
RETURN_ON_FAILED_EXECUTION(BigInt);
|
||||
RETURN_ESCAPED(Utils::ToLocal(result.ToHandleChecked()));
|
||||
}
|
||||
|
||||
uint64_t v8::BigInt::Uint64Value(bool* lossless) const {
|
||||
i::Handle<i::BigInt> handle = Utils::OpenHandle(this);
|
||||
return handle->AsUint64(lossless);
|
||||
}
|
||||
|
||||
int64_t v8::BigInt::Int64Value(bool* lossless) const {
|
||||
i::Handle<i::BigInt> handle = Utils::OpenHandle(this);
|
||||
return handle->AsInt64(lossless);
|
||||
}
|
||||
|
||||
int BigInt::WordCount() const {
|
||||
i::Handle<i::BigInt> handle = Utils::OpenHandle(this);
|
||||
return handle->Words64Count();
|
||||
}
|
||||
|
||||
void BigInt::ToWordsArray(int* sign_bit, int* word_count,
|
||||
uint64_t* words) const {
|
||||
i::Handle<i::BigInt> handle = Utils::OpenHandle(this);
|
||||
return handle->ToWordsArray64(sign_bit, word_count, words);
|
||||
}
|
||||
|
||||
void Isolate::ReportExternalAllocationLimitReached() {
|
||||
i::Heap* heap = reinterpret_cast<i::Isolate*>(this)->heap();
|
||||
if (heap->gc_state() != i::Heap::NOT_IN_GC) return;
|
||||
|
||||
Vendored
+1
@@ -127,6 +127,7 @@ class RegisteredExtension {
|
||||
V(Promise, JSPromise) \
|
||||
V(Primitive, Object) \
|
||||
V(PrimitiveArray, FixedArray) \
|
||||
V(BigInt, BigInt) \
|
||||
V(ScriptOrModule, Script)
|
||||
|
||||
class Utils {
|
||||
|
||||
Vendored
+1
@@ -692,6 +692,7 @@ class RuntimeCallTimer final {
|
||||
V(ArrayBuffer_New) \
|
||||
V(Array_CloneElementAt) \
|
||||
V(Array_New) \
|
||||
V(BigInt_NewFromWords) \
|
||||
V(BigInt64Array_New) \
|
||||
V(BigUint64Array_New) \
|
||||
V(BigIntObject_New) \
|
||||
|
||||
Vendored
+64
@@ -2259,6 +2259,70 @@ Handle<BigInt> BigInt::FromUint64(Isolate* isolate, uint64_t n) {
|
||||
return MutableBigInt::MakeImmutable(result);
|
||||
}
|
||||
|
||||
MaybeHandle<BigInt> BigInt::FromWords64(Isolate* isolate, int sign_bit,
|
||||
int words64_count,
|
||||
const uint64_t* words) {
|
||||
if (words64_count < 0 || words64_count > kMaxLength / (64 / kDigitBits)) {
|
||||
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
|
||||
BigInt);
|
||||
}
|
||||
if (words64_count == 0) return MutableBigInt::Zero(isolate);
|
||||
STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32);
|
||||
int length = (64 / kDigitBits) * words64_count;
|
||||
DCHECK_GT(length, 0);
|
||||
if (kDigitBits == 32 && words[words64_count - 1] <= (1ULL << 32)) length--;
|
||||
|
||||
Handle<MutableBigInt> result;
|
||||
if (!MutableBigInt::New(isolate, length).ToHandle(&result)) {
|
||||
return MaybeHandle<BigInt>();
|
||||
}
|
||||
|
||||
result->set_sign(sign_bit);
|
||||
if (kDigitBits == 64) {
|
||||
for (int i = 0; i < length; ++i) {
|
||||
result->set_digit(i, static_cast<digit_t>(words[i]));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
digit_t lo = static_cast<digit_t>(words[i / 2]);
|
||||
digit_t hi = static_cast<digit_t>(words[i / 2] >> 32);
|
||||
result->set_digit(i, lo);
|
||||
if (i + 1 < length) result->set_digit(i + 1, hi);
|
||||
}
|
||||
}
|
||||
|
||||
return MutableBigInt::MakeImmutable(result);
|
||||
}
|
||||
|
||||
int BigInt::Words64Count() {
|
||||
STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32);
|
||||
return length() / (64 / kDigitBits) +
|
||||
(kDigitBits == 32 && length() % 2 == 1 ? 1 : 0);
|
||||
}
|
||||
|
||||
void BigInt::ToWordsArray64(int* sign_bit, int* words64_count,
|
||||
uint64_t* words) {
|
||||
DCHECK_NE(sign_bit, nullptr);
|
||||
DCHECK_NE(words64_count, nullptr);
|
||||
*sign_bit = sign();
|
||||
int available_words = *words64_count;
|
||||
*words64_count = Words64Count();
|
||||
if (available_words == 0) return;
|
||||
DCHECK_NE(words, nullptr);
|
||||
|
||||
int len = length();
|
||||
if (kDigitBits == 64) {
|
||||
for (int i = 0; i < len && i < available_words; ++i) words[i] = digit(i);
|
||||
} else {
|
||||
for (int i = 0; i < len && available_words > 0; i += 2) {
|
||||
uint64_t lo = digit(i);
|
||||
uint64_t hi = (i + 1) < len ? digit(i + 1) : 0;
|
||||
words[i / 2] = lo | (hi << 32);
|
||||
available_words--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t MutableBigInt::GetRawBits(BigIntBase* x, bool* lossless) {
|
||||
if (lossless != nullptr) *lossless = true;
|
||||
if (x->is_zero()) return 0;
|
||||
|
||||
Vendored
+5
@@ -144,8 +144,13 @@ class V8_EXPORT_PRIVATE BigInt : public BigIntBase {
|
||||
|
||||
static Handle<BigInt> FromInt64(Isolate* isolate, int64_t n);
|
||||
static Handle<BigInt> FromUint64(Isolate* isolate, uint64_t n);
|
||||
static MaybeHandle<BigInt> FromWords64(Isolate* isolate, int sign_bit,
|
||||
int words64_count,
|
||||
const uint64_t* words);
|
||||
int64_t AsInt64(bool* lossless = nullptr);
|
||||
uint64_t AsUint64(bool* lossless = nullptr);
|
||||
int Words64Count();
|
||||
void ToWordsArray64(int* sign_bit, int* words64_count, uint64_t* words);
|
||||
|
||||
DECL_CAST(BigInt)
|
||||
DECL_VERIFIER(BigInt)
|
||||
|
||||
Vendored
+114
@@ -27805,3 +27805,117 @@ TEST(WasmStreamingAbortNoReject) {
|
||||
streaming.Abort({});
|
||||
CHECK_EQ(streaming.GetPromise()->State(), v8::Promise::kPending);
|
||||
}
|
||||
|
||||
TEST(BigIntAPI) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
bool lossless;
|
||||
uint64_t words1[10];
|
||||
uint64_t words2[10];
|
||||
|
||||
{
|
||||
Local<Value> bi = CompileRun("12n");
|
||||
CHECK(bi->IsBigInt());
|
||||
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 12);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless), 12);
|
||||
CHECK_EQ(lossless, true);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 12);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 12);
|
||||
CHECK_EQ(lossless, true);
|
||||
}
|
||||
|
||||
{
|
||||
Local<Value> bi = CompileRun("-12n");
|
||||
CHECK(bi->IsBigInt());
|
||||
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), static_cast<uint64_t>(-12));
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
|
||||
static_cast<uint64_t>(-12));
|
||||
CHECK_EQ(lossless, false);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -12);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), -12);
|
||||
CHECK_EQ(lossless, true);
|
||||
}
|
||||
|
||||
{
|
||||
Local<Value> bi = CompileRun("123456789012345678901234567890n");
|
||||
CHECK(bi->IsBigInt());
|
||||
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 14083847773837265618ULL);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
|
||||
14083847773837265618ULL);
|
||||
CHECK_EQ(lossless, false);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -4362896299872285998LL);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless),
|
||||
-4362896299872285998LL);
|
||||
CHECK_EQ(lossless, false);
|
||||
}
|
||||
|
||||
{
|
||||
Local<Value> bi = CompileRun("-123456789012345678901234567890n");
|
||||
CHECK(bi->IsBigInt());
|
||||
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 4362896299872285998LL);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
|
||||
4362896299872285998LL);
|
||||
CHECK_EQ(lossless, false);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 4362896299872285998LL);
|
||||
CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 4362896299872285998LL);
|
||||
CHECK_EQ(lossless, false);
|
||||
}
|
||||
|
||||
{
|
||||
Local<v8::BigInt> bi =
|
||||
v8::BigInt::NewFromWords(env.local(), 0, 0, words1).ToLocalChecked();
|
||||
CHECK_EQ(bi->Uint64Value(), 0);
|
||||
CHECK_EQ(bi->WordCount(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
TryCatch try_catch(isolate);
|
||||
v8::MaybeLocal<v8::BigInt> bi = v8::BigInt::NewFromWords(
|
||||
env.local(), 0, std::numeric_limits<int>::max(), words1);
|
||||
CHECK(bi.IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
|
||||
{
|
||||
TryCatch try_catch(isolate);
|
||||
v8::MaybeLocal<v8::BigInt> bi =
|
||||
v8::BigInt::NewFromWords(env.local(), 0, -1, words1);
|
||||
CHECK(bi.IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
|
||||
{
|
||||
TryCatch try_catch(isolate);
|
||||
v8::MaybeLocal<v8::BigInt> bi =
|
||||
v8::BigInt::NewFromWords(env.local(), 0, 1 << 30, words1);
|
||||
CHECK(bi.IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
|
||||
for (int sign_bit = 0; sign_bit <= 1; sign_bit++) {
|
||||
words1[0] = 0xffffffff00000000ULL;
|
||||
words1[1] = 0x00000000ffffffffULL;
|
||||
v8::Local<v8::BigInt> bi =
|
||||
v8::BigInt::NewFromWords(env.local(), sign_bit, 2, words1)
|
||||
.ToLocalChecked();
|
||||
CHECK_EQ(bi->Uint64Value(&lossless),
|
||||
sign_bit ? static_cast<uint64_t>(-static_cast<int64_t>(words1[0]))
|
||||
: words1[0]);
|
||||
CHECK_EQ(lossless, false);
|
||||
CHECK_EQ(bi->Int64Value(&lossless), sign_bit
|
||||
? -static_cast<int64_t>(words1[0])
|
||||
: static_cast<int64_t>(words1[0]));
|
||||
CHECK_EQ(lossless, false);
|
||||
CHECK_EQ(bi->WordCount(), 2);
|
||||
int real_sign_bit;
|
||||
int word_count = arraysize(words2);
|
||||
bi->ToWordsArray(&real_sign_bit, &word_count, words2);
|
||||
CHECK_EQ(real_sign_bit, sign_bit);
|
||||
CHECK_EQ(word_count, 2);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user