-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
napi: add bigint support #21226
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
napi: add bigint support #21226
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -926,7 +926,8 @@ const char* error_messages[] = {nullptr, | |
"Invalid handle scope usage", | ||
"Invalid callback scope usage", | ||
"Thread-safe function queue is full", | ||
"Thread-safe function handle is closing" | ||
"Thread-safe function handle is closing", | ||
"A bigint was expected", | ||
}; | ||
|
||
static inline napi_status napi_clear_last_error(napi_env env) { | ||
|
@@ -958,7 +959,7 @@ napi_status napi_get_last_error_info(napi_env env, | |
// We don't have a napi_status_last as this would result in an ABI | ||
// change each time a message was added. | ||
static_assert( | ||
node::arraysize(error_messages) == napi_closing + 1, | ||
node::arraysize(error_messages) == napi_bigint_expected + 1, | ||
"Count of error messages must match count of error values"); | ||
CHECK_LE(env->last_error.error_code, napi_callback_scope_mismatch); | ||
|
||
|
@@ -1713,6 +1714,58 @@ napi_status napi_create_int64(napi_env env, | |
return napi_clear_last_error(env); | ||
} | ||
|
||
napi_status napi_create_bigint_int64(napi_env env, | ||
int64_t value, | ||
napi_value* result) { | ||
CHECK_ENV(env); | ||
CHECK_ARG(env, result); | ||
|
||
*result = v8impl::JsValueFromV8LocalValue( | ||
v8::BigInt::New(env->isolate, value)); | ||
|
||
return napi_clear_last_error(env); | ||
} | ||
|
||
napi_status napi_create_bigint_uint64(napi_env env, | ||
uint64_t value, | ||
napi_value* result) { | ||
CHECK_ENV(env); | ||
CHECK_ARG(env, result); | ||
|
||
*result = v8impl::JsValueFromV8LocalValue( | ||
v8::BigInt::NewFromUnsigned(env->isolate, value)); | ||
|
||
return napi_clear_last_error(env); | ||
} | ||
|
||
napi_status napi_create_bigint_words(napi_env env, | ||
int sign_bit, | ||
size_t word_count, | ||
const uint64_t* words, | ||
napi_value* result) { | ||
NAPI_PREAMBLE(env); | ||
CHECK_ARG(env, words); | ||
CHECK_ARG(env, result); | ||
|
||
v8::Local<v8::Context> context = env->isolate->GetCurrentContext(); | ||
|
||
if (word_count > INT_MAX) { | ||
napi_throw_range_error(env, nullptr, "Maximum BigInt size exceeded"); | ||
return napi_set_last_error(env, napi_pending_exception); | ||
} | ||
|
||
v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords( | ||
context, sign_bit, word_count, words); | ||
|
||
if (try_catch.HasCaught()) { | ||
return napi_set_last_error(env, napi_pending_exception); | ||
} else { | ||
CHECK_MAYBE_EMPTY(env, b, napi_generic_failure); | ||
*result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked()); | ||
return napi_clear_last_error(env); | ||
} | ||
} | ||
|
||
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) { | ||
CHECK_ENV(env); | ||
CHECK_ARG(env, result); | ||
|
@@ -1878,6 +1931,8 @@ napi_status napi_typeof(napi_env env, | |
|
||
if (v->IsNumber()) { | ||
*result = napi_number; | ||
} else if (v->IsBigInt()) { | ||
*result = napi_bigint; | ||
} else if (v->IsString()) { | ||
*result = napi_string; | ||
} else if (v->IsFunction()) { | ||
|
@@ -2201,6 +2256,72 @@ napi_status napi_get_value_int64(napi_env env, | |
return napi_clear_last_error(env); | ||
} | ||
|
||
napi_status napi_get_value_bigint_int64(napi_env env, | ||
napi_value value, | ||
int64_t* result, | ||
bool* lossless) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nodejs/n-api Side note … did we make a conscious decision to allow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what did C use before There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @devsnek Any integral type, and macros representing true (usually 1) and false (0). |
||
CHECK_ENV(env); | ||
CHECK_ARG(env, value); | ||
CHECK_ARG(env, result); | ||
CHECK_ARG(env, lossless); | ||
|
||
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); | ||
|
||
RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected); | ||
|
||
*result = val.As<v8::BigInt>()->Int64Value(lossless); | ||
|
||
return napi_clear_last_error(env); | ||
} | ||
|
||
napi_status napi_get_value_bigint_uint64(napi_env env, | ||
napi_value value, | ||
uint64_t* result, | ||
bool* lossless) { | ||
CHECK_ENV(env); | ||
CHECK_ARG(env, value); | ||
CHECK_ARG(env, result); | ||
CHECK_ARG(env, lossless); | ||
|
||
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); | ||
|
||
RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected); | ||
|
||
*result = val.As<v8::BigInt>()->Uint64Value(lossless); | ||
|
||
return napi_clear_last_error(env); | ||
} | ||
|
||
napi_status napi_get_value_bigint_words(napi_env env, | ||
napi_value value, | ||
int* sign_bit, | ||
size_t* word_count, | ||
uint64_t* words) { | ||
CHECK_ENV(env); | ||
CHECK_ARG(env, value); | ||
CHECK_ARG(env, word_count); | ||
|
||
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); | ||
|
||
RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected); | ||
|
||
v8::Local<v8::BigInt> big = val.As<v8::BigInt>(); | ||
|
||
int word_count_int = *word_count; | ||
|
||
if (sign_bit == nullptr && words == nullptr) { | ||
word_count_int = big->WordCount(); | ||
} else { | ||
CHECK_ARG(env, sign_bit); | ||
CHECK_ARG(env, words); | ||
big->ToWordsArray(sign_bit, &word_count_int, words); | ||
} | ||
|
||
*word_count = word_count_int; | ||
|
||
return napi_clear_last_error(env); | ||
} | ||
|
||
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) { | ||
// Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw | ||
// JS exceptions. | ||
|
@@ -3139,6 +3260,14 @@ napi_status napi_create_typedarray(napi_env env, | |
CREATE_TYPED_ARRAY( | ||
env, Float64Array, 8, buffer, byte_offset, length, typedArray); | ||
break; | ||
case napi_bigint64_array: | ||
CREATE_TYPED_ARRAY( | ||
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray); | ||
break; | ||
case napi_biguint64_array: | ||
CREATE_TYPED_ARRAY( | ||
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray); | ||
break; | ||
default: | ||
return napi_set_last_error(env, napi_invalid_arg); | ||
} | ||
|
@@ -3181,6 +3310,10 @@ napi_status napi_get_typedarray_info(napi_env env, | |
*type = napi_float32_array; | ||
} else if (value->IsFloat64Array()) { | ||
*type = napi_float64_array; | ||
} else if (value->IsBigInt64Array()) { | ||
*type = napi_bigint64_array; | ||
} else if (value->IsBigUint64Array()) { | ||
*type = napi_biguint64_array; | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this tested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this should probably just return
napi_invalid_arg
.If we do throw an error, we should introduce a new error code.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #21226 (comment). The rationale is that there should be no difference in how
INT_MAX + 1ULL
andINT_MAX
are treated.