Skip to content

Commit efd23fd

Browse files
committed
node-api: add new napi_ref type for any napi_value
1 parent 4f9bc41 commit efd23fd

File tree

8 files changed

+447
-55
lines changed

8 files changed

+447
-55
lines changed

doc/api/n-api.md

+105-18
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,33 @@ minimum lifetimes explicitly.
721721

722722
For more details, review the [Object lifetime management][].
723723

724+
#### `node_api_reftype`
725+
726+
<!-- YAML
727+
added: REPLACEME
728+
-->
729+
730+
Type of the `napi_ref` reference.
731+
There are two types of reference:
732+
733+
* `node_api_reftype_strong_or_weak` - a reference to an object (`napi_object`)
734+
that can be a strong or a weak reference. References with ref count greater
735+
than 0 are strong references and references with ref count equal to 0 are
736+
weak references. The values referenced by weak references can be collected
737+
at any time by GC if there are no other strong references to the
738+
`napi_value`. To delete the reference we must use `napi_delete_reference`
739+
function.
740+
* `node_api_reftype_strong` - a strong reference to any type of `napi_value`.
741+
When the ref count goes down to 0, the reference is deleted.
742+
The `napi_delete_reference` function must not be used with the strong references.
743+
744+
```c
745+
typedef enum {
746+
node_api_reftype_strong_or_weak,
747+
node_api_reftype_strong,
748+
} node_api_reftype;
749+
```
750+
724751
#### `napi_type_tag`
725752

726753
<!-- YAML
@@ -1613,9 +1640,9 @@ If it is called more than once an error will be returned.
16131640

16141641
This API can be called even if there is a pending JavaScript exception.
16151642

1616-
### References to objects with a lifespan longer than that of the native method
1643+
### References to values with a lifespan longer than that of the native method
16171644

1618-
In some cases an addon will need to be able to create and reference objects
1645+
In some cases an addon will need to be able to create and reference values
16191646
with a lifespan longer than that of a single native method invocation. For
16201647
example, to create a constructor and later use that constructor
16211648
in a request to creates instances, it must be possible to reference
@@ -1625,39 +1652,80 @@ described in the earlier section. The lifespan of a normal handle is
16251652
managed by scopes and all scopes must be closed before the end of a native
16261653
method.
16271654

1628-
Node-API provides methods to create persistent references to an object.
1629-
Each persistent reference has an associated count with a value of 0
1630-
or higher. The count determines if the reference will keep
1655+
Node-API provides methods to create persistent references to a `napi_value`.
1656+
There are two types of references:
1657+
1658+
* `node_api_reftype_strong_or_weak` type is only for `napi_object` values.
1659+
* `node_api_reftype_strong` type is for any value type.
1660+
1661+
Each persistent strong/weak reference has an associated count with a value
1662+
of 0 or higher. The count determines if the reference will keep
16311663
the corresponding object live. References with a count of 0 do not
16321664
prevent the object from being collected and are often called 'weak'
16331665
references. Any count greater than 0 will prevent the object
16341666
from being collected.
16351667

1636-
References can be created with an initial reference count. The count can
1637-
then be modified through [`napi_reference_ref`][] and
1638-
[`napi_reference_unref`][]. If an object is collected while the count
1639-
for a reference is 0, all subsequent calls to
1640-
get the object associated with the reference [`napi_get_reference_value`][]
1668+
The strong reference can have a reference count of 1 or higher.
1669+
If the count becomes 0, then the reference is deleted.
1670+
1671+
Strong/weak references can be created with an initial reference count, while
1672+
the strong references always use the initial reference count 1.
1673+
The count can then be modified through [`napi_reference_ref`][] and
1674+
[`napi_reference_unref`][]. If an object is collected while the strong/weak
1675+
references count is 0, all subsequent calls to get the object associated with
1676+
the reference [`napi_get_reference_value`][]
16411677
will return `NULL` for the returned `napi_value`. An attempt to call
16421678
[`napi_reference_ref`][] for a reference whose object has been collected
16431679
results in an error.
16441680

1645-
References must be deleted once they are no longer required by the addon. When
1646-
a reference is deleted, it will no longer prevent the corresponding object from
1647-
being collected. Failure to delete a persistent reference results in
1648-
a 'memory leak' with both the native memory for the persistent reference and
1649-
the corresponding object on the heap being retained forever.
1681+
Strong/weak references must be deleted once they are no longer required by
1682+
the addon. When a reference is deleted, it will no longer prevent the
1683+
corresponding object from being collected. Failure to delete a persistent
1684+
reference results in a 'memory leak' with both the native memory for the
1685+
persistent reference and the corresponding object on the heap being retained
1686+
forever.
16501687

16511688
There can be multiple persistent references created which refer to the same
1652-
object, each of which will either keep the object live or not based on its
1653-
individual count. Multiple persistent references to the same object
1689+
value, each of which will either keep the value alive or not based on its
1690+
individual count. Multiple persistent references to the same value
16541691
can result in unexpectedly keeping alive native memory. The native structures
16551692
for a persistent reference must be kept alive until finalizers for the
16561693
referenced object are executed. If a new persistent reference is created
16571694
for the same object, the finalizers for that object will not be
16581695
run and the native memory pointed by the earlier persistent reference
16591696
will not be freed. This can be avoided by calling
1660-
`napi_delete_reference` in addition to `napi_reference_unref` when possible.
1697+
`napi_delete_reference` in addition to `napi_reference_unref` for strong/weak
1698+
references when possible. The `napi_delete_reference` must not be called for
1699+
the `node_api_reftype_strong` references because the reference is deleted
1700+
automatically after `napi_reference_unref` call sets reference count to 0.
1701+
1702+
#### `node_api_create_reference`
1703+
1704+
<!-- YAML
1705+
added: REPLACEME
1706+
-->
1707+
1708+
```c
1709+
NAPI_EXTERN napi_status node_api_create_reference(napi_env env,
1710+
napi_value value,
1711+
node_api_reftype reftype,
1712+
uint32_t initial_refcount,
1713+
napi_ref* result);
1714+
```
1715+
1716+
* `[in] env`: The environment that the API is invoked under.
1717+
* `[in] value`: `napi_value` to which we want to create a reference.
1718+
* `[in] reftype`: Type of the reference.
1719+
* `[in] initial_refcount`: Initial reference count for the new reference.
1720+
* `[out] result`: `napi_ref` pointing to the new reference.
1721+
1722+
Returns `napi_ok` if the API succeeded.
1723+
1724+
For the `node_api_reftype_strong_or_weak` `reftype` set `initial_refcount` to 0
1725+
for a weak reference, and value greater than 0 for a strong reference. It
1726+
accepts only `napi_object` values.
1727+
The `node_api_reftype_strong` ignores the `initial_refcount` and always uses 1.
1728+
It accept `napi_value` of any type.
16611729

16621730
#### `napi_create_reference`
16631731

@@ -1684,6 +1752,25 @@ Returns `napi_ok` if the API succeeded.
16841752
This API creates a new reference with the specified reference count
16851753
to the `Object` passed in.
16861754

1755+
#### `node_api_get_reference_type`
1756+
1757+
<!-- YAML
1758+
added: REPLACEME
1759+
-->
1760+
1761+
```c
1762+
NAPI_EXTERN napi_status node_api_get_reference_type(napi_env env,
1763+
napi_ref ref,
1764+
node_api_reftype* result);
1765+
```
1766+
1767+
* `[in] env`: The environment that the API is invoked under.
1768+
* `[in] ref`: `napi_ref` which type we want to get.
1769+
* `[out] result`: `node_api_reftype` type of the `ref`.
1770+
1771+
Returns `napi_ok` if the API succeeded and the `result` contains type of the
1772+
reference.
1773+
16871774
#### `napi_delete_reference`
16881775

16891776
<!-- YAML

src/js_native_api.h

+29-10
Original file line numberDiff line numberDiff line change
@@ -315,34 +315,53 @@ NAPI_EXTERN napi_status napi_get_value_external(napi_env env,
315315

316316
// Methods to control object lifespan
317317

318+
#ifdef NAPI_EXPERIMENTAL
319+
// For node_api_reftype_strong_or_weak set initial_refcount to 0 for a weak
320+
// reference, and value greater than 0 for a strong reference. The
321+
// node_api_reftype_strong ignores the initial_refcount and always uses 1.
322+
NAPI_EXTERN napi_status node_api_create_reference(napi_env env,
323+
napi_value value,
324+
node_api_reftype reftype,
325+
uint32_t initial_refcount,
326+
napi_ref* result);
327+
// Get type of the reference.
328+
NAPI_EXTERN napi_status node_api_get_reference_type(napi_env env,
329+
napi_ref ref,
330+
node_api_reftype* result);
331+
#endif
332+
333+
// Create node_api_reftype_strong_or_weak reference.
318334
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
319335
NAPI_EXTERN napi_status napi_create_reference(napi_env env,
320336
napi_value value,
321337
uint32_t initial_refcount,
322338
napi_ref* result);
323339

324-
// Deletes a reference. The referenced value is released, and may
325-
// be GC'd unless there are other references to it.
340+
// Delete a node_api_reftype_strong_or_weak reference. The referenced value is
341+
// released, and may be GC'd unless there are other references to it.
342+
// This method cannot be used with node_api_reftype_strong references.
326343
NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref);
327344

328-
// Increments the reference count, optionally returning the resulting count.
345+
// Increment the reference count, optionally returning the resulting count.
329346
// After this call the reference will be a strong reference because its
330347
// refcount is >0, and the referenced object is effectively "pinned".
331-
// Calling this when the refcount is 0 and the object is unavailable
332-
// results in an error.
333348
NAPI_EXTERN napi_status napi_reference_ref(napi_env env,
334349
napi_ref ref,
335350
uint32_t* result);
336351

337-
// Decrements the reference count, optionally returning the resulting count.
338-
// If the result is 0 the reference is now weak and the object may be GC'd
339-
// at any time if there are no other references. Calling this when the
340-
// refcount is already 0 results in an error.
352+
// Decrement the reference count, optionally returning the resulting count.
353+
// For node_api_reftype_strong_or_weak references if the result is 0, then the
354+
// reference is now weak and the object may be GC'd at any time if there are no
355+
// other references.
356+
// For node_api_reftype_strong references if the result is 0, then the
357+
// reference is deleted and the stored napi_value may be GC'd at any time if
358+
// there are no other references.
359+
// Calling this when the refcount is already 0 results in an error.
341360
NAPI_EXTERN napi_status napi_reference_unref(napi_env env,
342361
napi_ref ref,
343362
uint32_t* result);
344363

345-
// Attempts to get a referenced value. If the reference is weak,
364+
// Attempt to get a referenced value. If the reference is weak,
346365
// the value might no longer be available, in that case the call
347366
// is still successful but the result is NULL.
348367
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,

src/js_native_api_types.h

+7
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,11 @@ typedef struct {
154154
} napi_type_tag;
155155
#endif // NAPI_VERSION >= 8
156156

157+
#ifdef NAPI_EXPERIMENTAL
158+
typedef enum {
159+
node_api_reftype_strong_or_weak,
160+
node_api_reftype_strong,
161+
} node_api_reftype;
162+
#endif
163+
157164
#endif // SRC_JS_NATIVE_API_TYPES_H_

0 commit comments

Comments
 (0)