diff options
author | Gus Caplan <me@gus.host> | 2018-07-04 01:42:16 +0300 |
---|---|---|
committer | Michaƫl Zasso <targos@protonmail.com> | 2018-07-26 09:34:24 +0300 |
commit | a921aff334e4d8d1df012608ec1e8fef9a4a0968 (patch) | |
tree | 8ecd9370b9c1f4c8b089facaf897df9dc08940b0 /deps | |
parent | eea5aeea475afc0c97f8ce0af1675cfcea027d39 (diff) |
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>
Diffstat (limited to 'deps')
-rw-r--r-- | deps/v8/include/v8.h | 42 | ||||
-rw-r--r-- | deps/v8/src/api.cc | 43 | ||||
-rw-r--r-- | deps/v8/src/api.h | 1 | ||||
-rw-r--r-- | deps/v8/src/counters.h | 1 | ||||
-rw-r--r-- | deps/v8/src/objects/bigint.cc | 64 | ||||
-rw-r--r-- | deps/v8/src/objects/bigint.h | 5 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-api.cc | 114 |
7 files changed, 270 insertions, 0 deletions
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index b68d9fbbfc3..6c56f918e3d 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -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: diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 34b4773c2f4..66ca4bb96ab 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -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; diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index d1297c8f38c..342ab855ac0 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -127,6 +127,7 @@ class RegisteredExtension { V(Promise, JSPromise) \ V(Primitive, Object) \ V(PrimitiveArray, FixedArray) \ + V(BigInt, BigInt) \ V(ScriptOrModule, Script) class Utils { diff --git a/deps/v8/src/counters.h b/deps/v8/src/counters.h index 95812cf5187..255c8db7c6b 100644 --- a/deps/v8/src/counters.h +++ b/deps/v8/src/counters.h @@ -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) \ diff --git a/deps/v8/src/objects/bigint.cc b/deps/v8/src/objects/bigint.cc index 3a0bb0fba33..61de3a066a2 100644 --- a/deps/v8/src/objects/bigint.cc +++ b/deps/v8/src/objects/bigint.cc @@ -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; diff --git a/deps/v8/src/objects/bigint.h b/deps/v8/src/objects/bigint.h index 7c36a474366..e6547389343 100644 --- a/deps/v8/src/objects/bigint.h +++ b/deps/v8/src/objects/bigint.h @@ -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) diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index a827c886ce9..953648fe427 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -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); + } +} |