-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
napi: add bigint support #21226
Conversation
df04ae3
to
5e695db
Compare
It's not entirely clear what is expected from a BigInt API in V8. You can discuss here: https://bugs.chromium.org/p/v8/issues/detail?id=7712 |
This should also wait until we have completed #19962 which will be updated so new functions go in initially as experimental. |
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.
Making as changes requested so that it does not land until we document how to guard as experimental initially.
73faabe
to
9474d13
Compare
9474d13
to
6000350
Compare
6000350
to
f5e1a37
Compare
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.
Missing documentation. Particularly important is the question of endianness for the word array-based functions.
src/node_api.cc
Outdated
RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected); | ||
|
||
val.As<v8::BigInt>()->ToWordsArray( | ||
sign_bit, reinterpret_cast<int*>(word_count), words); |
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.
The most significant part of word_count
might not get cleared after the cast.
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.
how should i fix this
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.
just word_count = 0;
before executing ToWordsArray
src/node_api.cc
Outdated
v8::Local<v8::Context> context = env->isolate->GetCurrentContext(); | ||
|
||
v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords( | ||
context, reinterpret_cast<int>(sign_bit), word_count, words); |
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.
We should throw when word_count > INT_MAX
.
src/node_api_types.h
Outdated
@@ -68,6 +75,9 @@ typedef enum { | |||
napi_name_expected, | |||
napi_function_expected, | |||
napi_number_expected, | |||
#ifdef NAPI_EXPERIMENTAL |
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.
I don't think it's really necessary to gate them with NAPI_EXPERIMENTAL, just the new functions.
Do you agree @mhdawson @digitalinfinity @gabrielschulhof
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.
Perhaps we must not gate here because if two APIs (such as thread_safe
and bigint
) add new status codes while in experimental, they will have to come out of experimental in the order their added status codes appear, otherwise their emergence from experimental will itself constitute an ABI break, since their status codes would have to be moved before the bracket.
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.
/me go PR the removal of the gate now 🙂
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.
This also means that if we backport bigint
but not thread_safe
, we'll have to backport the status codes added by thread_safe
so that the status codes for bigint
will have the same value betweeen the backport and the current version.
src/node_api_types.h
Outdated
@@ -68,6 +75,9 @@ typedef enum { | |||
napi_name_expected, | |||
napi_function_expected, | |||
napi_number_expected, | |||
#ifdef NAPI_EXPERIMENTAL | |||
napi_bigint_expected, | |||
#endif // NAPI_EXPERIMENTAL |
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.
We should only ever add enum values to the bottom since they need to be stable over time.
src/node_api_types.h
Outdated
@@ -41,6 +41,9 @@ typedef enum { | |||
napi_null, | |||
napi_boolean, | |||
napi_number, | |||
#ifdef NAPI_EXPERIMENTAL | |||
napi_bigint, |
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.
Same here, we want existing values to remain unchanged.
src/node_api.h
Outdated
@@ -635,6 +635,34 @@ NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(napi_env env, | |||
|
|||
#ifdef NAPI_EXPERIMENTAL | |||
|
|||
NAPI_EXTERN napi_status napi_create_bigint_int64(napi_env env, |
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.
nit: can we add these after the existing ones?
doc/api/n-api.md
Outdated
@@ -105,6 +105,9 @@ typedef enum { | |||
napi_name_expected, | |||
napi_function_expected, | |||
napi_number_expected, | |||
#ifdef NAPI_EXPERIMENTAL | |||
napi_bigint_expected, |
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.
This value should go to the end of the enum, otherwise we break ABI. Once you've moved it to the end of the enum, you also need to append a string explaining the error message to the end of the array of error messages, otherwise you get a failed assertion.
doc/api/n-api.md
Outdated
@@ -1220,6 +1223,9 @@ typedef enum { | |||
napi_null, | |||
napi_boolean, | |||
napi_number, | |||
#ifdef NAPI_EXPERIMENTAL | |||
napi_bigint, |
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.
Ditto.
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.
We should only be adding to existing enums, not inserting new values.
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.
I'd also like to mention in the docs that the output may be undefined if a method fails. Consider napi_get_value_bigint_words()
. I'd assume the content of sign_bit
to be indeterminate if that function fails for whatever reason.
doc/api/n-api.md
Outdated
|
||
Returns `napi_ok` if the API succeeded. | ||
|
||
This API is used to convert the C `int64_t` type to the JavaScript `BigInt` |
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.
s/is used to convert/converts/
Ditto below.
doc/api/n-api.md
Outdated
|
||
The resulting number is calculated as: | ||
|
||
`(-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...)` |
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.
The format could probably be improved a bit:
(–1)sign_bit
(words[0]
× (264)0 + words[1]
× (264)1 + …)
TBH I'd still like to see a declarative explanation of what this means ("words is expressed in little endian").
doc/api/n-api.md
Outdated
- `[out] result`: A `napi_value` representing a JavaScript `BigInt`. | ||
|
||
Returns `napi_ok` if the API succeeded. | ||
|
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.
Missing a small blurb of what the function does, like the other functions do.
This API converts an array of unsigned 64-bit words into a single
BigInt
value.
doc/api/n-api.md
Outdated
- `[in] value`: `napi_value` represenging JavaScript `BigInt`. | ||
- `[out] result`: C int64_t primitive equivalent of the given JavaScript | ||
`BigInt`. | ||
- `[out] lossless`: Indicates if the bigint value was truncated losslessly. |
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.
Inconsistent capitalization: decide on BigInt
or BigInt.
doc/api/n-api.md
Outdated
``` | ||
|
||
- `[in] env`: The environment that the API is invoked under | ||
- `[in] value`: `napi_value` represenging JavaScript `BigInt`. |
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.
typo: representing
doc/api/n-api.md
Outdated
`napi_bigint_expected`. | ||
|
||
This API returns the C int64_t primitive equivalent of the given JavaScript | ||
`BigInt`. If needed it will truncate the value, setting `lossless` to `true`. |
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.
This behavior sounds a bit counterintuitive to me: doesn't truncation lose some value? Why is lossless
set to true then?
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.
typo :P
doc/api/n-api.md
Outdated
```C | ||
napi_status napi_get_bigint_word_count(napi_env env, | ||
napi_value value, | ||
size_t* word_count); |
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.
Instead of a separate API, could we instead make the functionality included in napi_get_value_bigint_words() when words pointer is set to NULL?
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.
this would require also having to set sign_bit
to NULL
but i like the idea, will work on it.
doc/api/n-api.md
Outdated
- `[out] words`: Pointer to 64-bit word array. | ||
|
||
Returns `napi_ok` if the API succeeded. | ||
|
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.
Also missing a sentence describing what the function does. I'd rather the longer descriptions in the parameter list be moved down here.
doc/api/n-api.md
Outdated
- `[in] value`: `napi_value` representing JavaScript `BigInt`. | ||
- `[out] sign_bit`: Integer representing if the JavaScript `BigInt` is positive | ||
or negative. | ||
- `[out] word_count`: Must be initialized to the length of the `words` 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.
I know this convention hasn't been used in the document yet, but [in/out]
?
src/node_api.cc
Outdated
v8::Local<v8::Context> context = env->isolate->GetCurrentContext(); | ||
|
||
if (word_count > INT_MAX) { | ||
return napi_set_last_error(env, napi_generic_failure); |
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.
I'd rather this be consistent with what V8 does when the word count is too big, which is to throw a RangeError
.
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.
if v8 handles it, all we have to do is nothing... right? the try_catch should carry the error
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.
No, V8 only handles the error conditions within the range of int
. We still need to handle the cases of greater than INT_MAX
.
fe73e59
to
5102bd1
Compare
not really sure what happened but its back to throwing |
doc/api/n-api.md
Outdated
- `[in/out] word_count`: Must 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`. | ||
- `[out] words`: Pointer to 64-bit word 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.
It should probably indicate that the words array needs to be pre-allocated for clarity.
test/addons-napi/test_bigint/test.js
Outdated
assert.strictEqual(num, TestUint64(num)); | ||
} | ||
assert.strictEqual(num, TestWords(num)); | ||
}); |
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.
It would probably be good to have a test or two for "lossy" conversions.
landing tomorrow afternoon (cst) if no one objects by then |
landed in 1849a2b |
PR-URL: #21226 Reviewed-By: Gabriel Schulhof <[email protected]> Reviewed-By: Kyle Farnung <[email protected]>
PR-URL: #21226 Reviewed-By: Gabriel Schulhof <[email protected]> Reviewed-By: Kyle Farnung <[email protected]>
Notable changes: * console: * The `console.timeLog()` method has been implemented. (#21312) * deps: * Upgrade to libuv 1.22.0. (#21731) * Upgrade to ICU 62.1 (Unicode 11, CLDR 33.1). (#21728) * http: * Added support for passing both `timeout` and `agent` options to `http.request`. (#21204) * napi: * Added experimental support for functions dealing with bigint numbers. (#21226) * process: * The `process.hrtime.bigint()` method has been implemented. (#21256) * Added the `--title` command line argument to set the process title on startup. (#21477) * trace_events: * Added process_name metadata. (#21477)
Notable changes: * console: * The `console.timeLog()` method has been implemented. (#21312) * deps: * Upgrade to libuv 1.22.0. (#21731) * Upgrade to ICU 62.1 (Unicode 11, CLDR 33.1). (#21728) * http: * Added support for passing both `timeout` and `agent` options to `http.request`. (#21204) * napi: * Added experimental support for functions dealing with bigint numbers. (#21226) * process: * The `process.hrtime.bigint()` method has been implemented. (#21256) * Added the `--title` command line argument to set the process title on startup. (#21477) * trace_events: * Added process_name metadata. (#21477) * Added new collaborators * codebytere - Shelley Vohr PR-URL: #21851
Notable changes: * console: * The `console.timeLog()` method has been implemented. (#21312) * deps: * Upgrade to libuv 1.22.0. (#21731) * Upgrade to ICU 62.1 (Unicode 11, CLDR 33.1). (#21728) * http: * Added support for passing both `timeout` and `agent` options to `http.request`. (#21204) * inspector: * Expose the original console API in `require('inspector').console`. (#21659) * napi: * Added experimental support for functions dealing with bigint numbers. (#21226) * process: * The `process.hrtime.bigint()` method has been implemented. (#21256) * Added the `--title` command line argument to set the process title on startup. (#21477) * trace_events: * Added process_name metadata. (#21477) * Added new collaborators * codebytere - Shelley Vohr PR-URL: #21851
Notable changes: * console: * The `console.timeLog()` method has been implemented. (#21312) * deps: * Upgrade to libuv 1.22.0. (#21731) * Upgrade to ICU 62.1 (Unicode 11, CLDR 33.1). (#21728) * http: * Added support for passing both `timeout` and `agent` options to `http.request`. (#21204) * inspector: * Expose the original console API in `require('inspector').console`. (#21659) * napi: * Added experimental support for functions dealing with bigint numbers. (#21226) * process: * The `process.hrtime.bigint()` method has been implemented. (#21256) * Added the `--title` command line argument to set the process title on startup. (#21477) * trace_events: * Added process_name metadata. (#21477) * Added new collaborators * codebytere - Shelley Vohr PR-URL: #21851
Checklist
/cc @nodejs/n-api passing a bigint to a napi function still throws
Invalid argument
and i can't figure out why./cc @nodejs/v8 should we block on this until we have a way to get values from bigint?
make -j4 test
(UNIX), orvcbuild test
(Windows) passes