Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deps: cherry-pick 477df06 from upstream v8 #21644

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -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.13',
'v8_embedder_string': '-node.14',

# Enable disassembler for `--print-code` v8 options
'v8_enable_disassembler': 1,
Expand Down
42 changes: 42 additions & 0 deletions deps/v8/include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -3048,6 +3048,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:
Expand Down
43 changes: 43 additions & 0 deletions deps/v8/src/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8121,6 +8121,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;
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class RegisteredExtension {
V(Promise, JSPromise) \
V(Primitive, Object) \
V(PrimitiveArray, FixedArray) \
V(BigInt, BigInt) \
V(ScriptOrModule, Script)

class Utils {
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/counters.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
64 changes: 64 additions & 0 deletions deps/v8/src/objects/bigint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2205,6 +2205,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;
Expand Down
5 changes: 5 additions & 0 deletions deps/v8/src/objects/bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
114 changes: 114 additions & 0 deletions deps/v8/test/cctest/test-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27613,3 +27613,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);
}
}