Skip to content

Commit 3096ee5

Browse files
devsnektargos
authored andcommitted
napi: add bigint support
PR-URL: #21226 Reviewed-By: Gabriel Schulhof <[email protected]> Reviewed-By: Kyle Farnung <[email protected]>
1 parent 27d17d4 commit 3096ee5

File tree

8 files changed

+523
-6
lines changed

8 files changed

+523
-6
lines changed

doc/api/n-api.md

+162-2
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,9 @@ typedef enum {
113113
napi_escape_called_twice,
114114
napi_handle_scope_mismatch,
115115
napi_callback_scope_mismatch,
116-
#ifdef NAPI_EXPERIMENTAL
117116
napi_queue_full,
118117
napi_closing,
119-
#endif // NAPI_EXPERIMENTAL
118+
napi_bigint_expected,
120119
} napi_status;
121120
```
122121
If additional information is required upon an API returning a failed status,
@@ -1225,6 +1224,7 @@ typedef enum {
12251224
napi_object,
12261225
napi_function,
12271226
napi_external,
1227+
napi_bigint,
12281228
} napi_valuetype;
12291229
```
12301230

@@ -1250,6 +1250,8 @@ typedef enum {
12501250
napi_uint32_array,
12511251
napi_float32_array,
12521252
napi_float64_array,
1253+
napi_bigint64_array,
1254+
napi_biguint64_array,
12531255
} napi_typedarray_type;
12541256
```
12551257

@@ -1691,6 +1693,78 @@ This API is used to convert from the C `double` type to the JavaScript
16911693
The JavaScript `Number` type is described in
16921694
[Section 6.1.6][] of the ECMAScript Language Specification.
16931695

1696+
#### napi_create_bigint_int64
1697+
<!-- YAML
1698+
added: REPLACEME
1699+
-->
1700+
1701+
> Stability: 1 - Experimental
1702+
1703+
```C
1704+
napi_status napi_create_bigint_int64(napi_env env,
1705+
int64_t value,
1706+
napi_value* result);
1707+
```
1708+
1709+
- `[in] env`: The environment that the API is invoked under.
1710+
- `[in] value`: Integer value to be represented in JavaScript.
1711+
- `[out] result`: A `napi_value` representing a JavaScript `BigInt`.
1712+
1713+
Returns `napi_ok` if the API succeeded.
1714+
1715+
This API converts the C `int64_t` type to the JavaScript `BigInt` type.
1716+
1717+
#### napi_create_bigint_uint64
1718+
<!-- YAML
1719+
added: REPLACEME
1720+
-->
1721+
1722+
> Stability: 1 - Experimental
1723+
1724+
```C
1725+
napi_status napi_create_bigint_uint64(napi_env env,
1726+
uint64_t vaue,
1727+
napi_value* result);
1728+
```
1729+
1730+
- `[in] env`: The environment that the API is invoked under.
1731+
- `[in] value`: Unsigned integer value to be represented in JavaScript.
1732+
- `[out] result`: A `napi_value` representing a JavaScript `BigInt`.
1733+
1734+
Returns `napi_ok` if the API succeeded.
1735+
1736+
This API converts the C `uint64_t` type to the JavaScript `BigInt` type.
1737+
1738+
#### napi_create_bigint_words
1739+
<!-- YAML
1740+
added: REPLACEME
1741+
-->
1742+
1743+
> Stability: 1 - Experimental
1744+
1745+
```C
1746+
napi_status napi_create_bigint_words(napi_env env,
1747+
int sign_bit,
1748+
size_t word_count,
1749+
const uint64_t* words,
1750+
napi_value* result);
1751+
```
1752+
1753+
- `[in] env`: The environment that the API is invoked under.
1754+
- `[in] sign_bit`: Determines if the resulting `BigInt` will be positive or
1755+
negative.
1756+
- `[in] word_count`: The length of the `words` array.
1757+
- `[in] words`: An array of `uint64_t` little-endian 64-bit words.
1758+
- `[out] result`: A `napi_value` representing a JavaScript `BigInt`.
1759+
1760+
Returns `napi_ok` if the API succeeded.
1761+
1762+
This API converts an array of unsigned 64-bit words into a single `BigInt`
1763+
value.
1764+
1765+
The resulting `BigInt` is calculated as: (–1)<sup>`sign_bit`</sup> (`words[0]`
1766+
× (2<sup>64</sup>)<sup>0</sup> + `words[1]` × (2<sup>64</sup>)<sup>1</sup> + …)
1767+
16941768
#### napi_create_string_latin1
16951769
<!-- YAML
16961770
added: v8.0.0
@@ -1975,6 +2049,92 @@ in it returns `napi_number_expected`.
19752049
This API returns the C double primitive equivalent of the given JavaScript
19762050
`Number`.
19772051

2052+
#### napi_get_value_bigint_int64
2053+
<!-- YAML
2054+
added: REPLACEME
2055+
-->
2056+
2057+
> Stability: 1 - Experimental
2058+
2059+
```C
2060+
napi_status napi_get_value_bigint_int64(napi_env env,
2061+
napi_value value,
2062+
int64_t* result,
2063+
bool* lossless);
2064+
```
2065+
2066+
- `[in] env`: The environment that the API is invoked under
2067+
- `[in] value`: `napi_value` representing JavaScript `BigInt`.
2068+
- `[out] result`: C `int64_t` primitive equivalent of the given JavaScript
2069+
`BigInt`.
2070+
- `[out] lossless`: Indicates whether the `BigInt` value was converted
2071+
losslessly.
2072+
2073+
Returns `napi_ok` if the API succeeded. If a non-`BigInt` is passed in it
2074+
returns `napi_bigint_expected`.
2075+
2076+
This API returns the C `int64_t` primitive equivalent of the given JavaScript
2077+
`BigInt`. If needed it will truncate the value, setting `lossless` to `false`.
2078+
2079+
2080+
#### napi_get_value_bigint_uint64
2081+
<!-- YAML
2082+
added: REPLACEME
2083+
-->
2084+
2085+
> Stability: 1 - Experimental
2086+
2087+
```C
2088+
napi_status napi_get_value_bigint_uint64(napi_env env,
2089+
napi_value value,
2090+
uint64_t* result,
2091+
bool* lossless);
2092+
```
2093+
2094+
- `[in] env`: The environment that the API is invoked under.
2095+
- `[in] value`: `napi_value` representing JavaScript `BigInt`.
2096+
- `[out] result`: C `uint64_t` primitive equivalent of the given JavaScript
2097+
`BigInt`.
2098+
- `[out] lossless`: Indicates whether the `BigInt` value was converted
2099+
losslessly.
2100+
2101+
Returns `napi_ok` if the API succeeded. If a non-`BigInt` is passed in it
2102+
returns `napi_bigint_expected`.
2103+
2104+
This API returns the C `uint64_t` primitive equivalent of the given JavaScript
2105+
`BigInt`. If needed it will truncate the value, setting `lossless` to `false`.
2106+
2107+
2108+
#### napi_get_value_bigint_words
2109+
<!-- YAML
2110+
added: REPLACEME
2111+
-->
2112+
2113+
> Stability: 1 - Experimental
2114+
2115+
```C
2116+
napi_status napi_get_value_bigint_words(napi_env env,
2117+
napi_value value,
2118+
size_t* word_count,
2119+
int* sign_bit,
2120+
uint64_t* words);
2121+
```
2122+
2123+
- `[in] env`: The environment that the API is invoked under.
2124+
- `[in] value`: `napi_value` representing JavaScript `BigInt`.
2125+
- `[out] sign_bit`: Integer representing if the JavaScript `BigInt` is positive
2126+
or negative.
2127+
- `[in/out] word_count`: Must be initialized to the length of the `words`
2128+
array. Upon return, it will be set to the actual number of words that
2129+
would be needed to store this `BigInt`.
2130+
- `[out] words`: Pointer to a pre-allocated 64-bit word array.
2131+
2132+
Returns `napi_ok` if the API succeeded.
2133+
2134+
This API converts a single `BigInt` value into a sign bit, 64-bit little-endian
2135+
array, and the number of elements in the array. `sign_bit` and `words` may be
2136+
both set to `NULL`, in order to get only `word_count`.
2137+
19782138
#### napi_get_value_external
19792139
<!-- YAML
19802140
added: v8.0.0

src/node_api.cc

+135-2
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,8 @@ const char* error_messages[] = {nullptr,
926926
"Invalid handle scope usage",
927927
"Invalid callback scope usage",
928928
"Thread-safe function queue is full",
929-
"Thread-safe function handle is closing"
929+
"Thread-safe function handle is closing",
930+
"A bigint was expected",
930931
};
931932

932933
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,
958959
// We don't have a napi_status_last as this would result in an ABI
959960
// change each time a message was added.
960961
static_assert(
961-
node::arraysize(error_messages) == napi_closing + 1,
962+
node::arraysize(error_messages) == napi_bigint_expected + 1,
962963
"Count of error messages must match count of error values");
963964
CHECK_LE(env->last_error.error_code, napi_callback_scope_mismatch);
964965

@@ -1713,6 +1714,58 @@ napi_status napi_create_int64(napi_env env,
17131714
return napi_clear_last_error(env);
17141715
}
17151716

1717+
napi_status napi_create_bigint_int64(napi_env env,
1718+
int64_t value,
1719+
napi_value* result) {
1720+
CHECK_ENV(env);
1721+
CHECK_ARG(env, result);
1722+
1723+
*result = v8impl::JsValueFromV8LocalValue(
1724+
v8::BigInt::New(env->isolate, value));
1725+
1726+
return napi_clear_last_error(env);
1727+
}
1728+
1729+
napi_status napi_create_bigint_uint64(napi_env env,
1730+
uint64_t value,
1731+
napi_value* result) {
1732+
CHECK_ENV(env);
1733+
CHECK_ARG(env, result);
1734+
1735+
*result = v8impl::JsValueFromV8LocalValue(
1736+
v8::BigInt::NewFromUnsigned(env->isolate, value));
1737+
1738+
return napi_clear_last_error(env);
1739+
}
1740+
1741+
napi_status napi_create_bigint_words(napi_env env,
1742+
int sign_bit,
1743+
size_t word_count,
1744+
const uint64_t* words,
1745+
napi_value* result) {
1746+
NAPI_PREAMBLE(env);
1747+
CHECK_ARG(env, words);
1748+
CHECK_ARG(env, result);
1749+
1750+
v8::Local<v8::Context> context = env->isolate->GetCurrentContext();
1751+
1752+
if (word_count > INT_MAX) {
1753+
napi_throw_range_error(env, nullptr, "Maximum BigInt size exceeded");
1754+
return napi_set_last_error(env, napi_pending_exception);
1755+
}
1756+
1757+
v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1758+
context, sign_bit, word_count, words);
1759+
1760+
if (try_catch.HasCaught()) {
1761+
return napi_set_last_error(env, napi_pending_exception);
1762+
} else {
1763+
CHECK_MAYBE_EMPTY(env, b, napi_generic_failure);
1764+
*result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1765+
return napi_clear_last_error(env);
1766+
}
1767+
}
1768+
17161769
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
17171770
CHECK_ENV(env);
17181771
CHECK_ARG(env, result);
@@ -1878,6 +1931,8 @@ napi_status napi_typeof(napi_env env,
18781931

18791932
if (v->IsNumber()) {
18801933
*result = napi_number;
1934+
} else if (v->IsBigInt()) {
1935+
*result = napi_bigint;
18811936
} else if (v->IsString()) {
18821937
*result = napi_string;
18831938
} else if (v->IsFunction()) {
@@ -2201,6 +2256,72 @@ napi_status napi_get_value_int64(napi_env env,
22012256
return napi_clear_last_error(env);
22022257
}
22032258

2259+
napi_status napi_get_value_bigint_int64(napi_env env,
2260+
napi_value value,
2261+
int64_t* result,
2262+
bool* lossless) {
2263+
CHECK_ENV(env);
2264+
CHECK_ARG(env, value);
2265+
CHECK_ARG(env, result);
2266+
CHECK_ARG(env, lossless);
2267+
2268+
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2269+
2270+
RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2271+
2272+
*result = val.As<v8::BigInt>()->Int64Value(lossless);
2273+
2274+
return napi_clear_last_error(env);
2275+
}
2276+
2277+
napi_status napi_get_value_bigint_uint64(napi_env env,
2278+
napi_value value,
2279+
uint64_t* result,
2280+
bool* lossless) {
2281+
CHECK_ENV(env);
2282+
CHECK_ARG(env, value);
2283+
CHECK_ARG(env, result);
2284+
CHECK_ARG(env, lossless);
2285+
2286+
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2287+
2288+
RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2289+
2290+
*result = val.As<v8::BigInt>()->Uint64Value(lossless);
2291+
2292+
return napi_clear_last_error(env);
2293+
}
2294+
2295+
napi_status napi_get_value_bigint_words(napi_env env,
2296+
napi_value value,
2297+
int* sign_bit,
2298+
size_t* word_count,
2299+
uint64_t* words) {
2300+
CHECK_ENV(env);
2301+
CHECK_ARG(env, value);
2302+
CHECK_ARG(env, word_count);
2303+
2304+
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2305+
2306+
RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2307+
2308+
v8::Local<v8::BigInt> big = val.As<v8::BigInt>();
2309+
2310+
int word_count_int = *word_count;
2311+
2312+
if (sign_bit == nullptr && words == nullptr) {
2313+
word_count_int = big->WordCount();
2314+
} else {
2315+
CHECK_ARG(env, sign_bit);
2316+
CHECK_ARG(env, words);
2317+
big->ToWordsArray(sign_bit, &word_count_int, words);
2318+
}
2319+
2320+
*word_count = word_count_int;
2321+
2322+
return napi_clear_last_error(env);
2323+
}
2324+
22042325
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) {
22052326
// Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
22062327
// JS exceptions.
@@ -3139,6 +3260,14 @@ napi_status napi_create_typedarray(napi_env env,
31393260
CREATE_TYPED_ARRAY(
31403261
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
31413262
break;
3263+
case napi_bigint64_array:
3264+
CREATE_TYPED_ARRAY(
3265+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3266+
break;
3267+
case napi_biguint64_array:
3268+
CREATE_TYPED_ARRAY(
3269+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3270+
break;
31423271
default:
31433272
return napi_set_last_error(env, napi_invalid_arg);
31443273
}
@@ -3181,6 +3310,10 @@ napi_status napi_get_typedarray_info(napi_env env,
31813310
*type = napi_float32_array;
31823311
} else if (value->IsFloat64Array()) {
31833312
*type = napi_float64_array;
3313+
} else if (value->IsBigInt64Array()) {
3314+
*type = napi_bigint64_array;
3315+
} else if (value->IsBigUint64Array()) {
3316+
*type = napi_biguint64_array;
31843317
}
31853318
}
31863319

0 commit comments

Comments
 (0)