Skip to content

Commit

Permalink
Rename node_api_reftype enum items
Browse files Browse the repository at this point in the history
  • Loading branch information
vmoroz committed May 27, 2022
1 parent ceb65e7 commit 4f8cbed
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 64 deletions.
76 changes: 42 additions & 34 deletions doc/api/n-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -727,25 +727,27 @@ For more details, review the [Object lifetime management][].
added: REPLACEME
-->

> Stability: 1 - Experimental

Type of the `napi_ref` reference.
There are two types of reference:

* `node_api_reftype_strong_or_weak` - a reference to an object (`napi_object`)
that can be a strong or a weak reference. References with ref count greater
than 0 are strong references and references with ref count equal to 0 are
weak references. The values referenced by weak references can be collected
at any time by GC if there are no other strong references to the
`napi_value`. To delete the reference we must use `napi_delete_reference`
function.
* `node_api_reftype_strong` - a strong reference to any type of `napi_value`.
When the ref count goes down to 0, the reference is deleted.
The `napi_delete_reference` function must not be used with the strong
references.
* `node_api_reftype_maybe_weak` - a reference to an object (`napi_object`) or a
function (`napi_function`) that can be a strong or a weak reference.
References with ref count greater than 0 are strong references and references
with ref count equal to 0 are weak references. The values referenced by weak
references can be collected at any time by GC if there are no other strong
references to the `napi_value`. To delete the reference we must use
`napi_delete_reference` function.

```c
typedef enum {
node_api_reftype_strong_or_weak,
node_api_reftype_strong,
node_api_reftype_maybe_weak,
} node_api_reftype;
```

Expand Down Expand Up @@ -1660,35 +1662,36 @@ method.
Node-API provides methods to create persistent references to a `napi_value`.
There are two types of references:

* `node_api_reftype_strong_or_weak` type is only for `napi_object` values.
* `node_api_reftype_strong` type is for any value type.
* `node_api_reftype_maybe_weak` type is only for `napi_object` and
`napi_function` values.

Each persistent strong/weak reference has an associated count with a value
of 0 or higher. The count determines if the reference will keep
the corresponding object live. References with a count of 0 do not
The `node_api_reftype_strong` reference has an associated count with a value of
1 or higher. If the reference count becomes 0, then the reference is deleted.

The `node_api_reftype_maybe_weak` reference has an associated count with a
value of 0 or higher. The count determines if the reference will keep
the corresponding object alive. References with a count of 0 do not
prevent the object from being collected and are often called 'weak'
references. Any count greater than 0 will prevent the object
from being collected.

The strong reference can have a reference count of 1 or higher.
If the count becomes 0, then the reference is deleted.

Strong/weak references can be created with an initial reference count, while
the strong references always use the initial reference count 1.
The count can then be modified through [`napi_reference_ref`][] and
[`napi_reference_unref`][]. If an object is collected while the strong/weak
references count is 0, all subsequent calls to get the object associated with
References can be created with an initial reference count. The count can then
be modified through [`napi_reference_ref`][] and
[`napi_reference_unref`][]. If an object is collected while the
`node_api_reftype_object` references count is 0, all subsequent calls to get
the object associated with
the reference [`napi_get_reference_value`][]
will return `NULL` for the returned `napi_value`. An attempt to call
[`napi_reference_ref`][] for a reference whose object has been collected
results in an error.

Strong/weak references must be deleted once they are no longer required by
the addon. When a reference is deleted, it will no longer prevent the
corresponding object from being collected. Failure to delete a persistent
reference results in a 'memory leak' with both the native memory for the
persistent reference and the corresponding object on the heap being retained
forever.
The `node_api_reftype_maybe_weak` references must be deleted once they are no
longer required by the addon. When a reference is deleted, it will no longer
prevent the corresponding object from being collected. Failure to delete a
persistent reference results in a 'memory leak' with both the native memory for
the persistent reference and the corresponding object on the heap being
retained forever.

There can be multiple persistent references created which refer to the same
value, each of which will either keep the value alive or not based on its
Expand All @@ -1699,17 +1702,20 @@ referenced object are executed. If a new persistent reference is created
for the same object, the finalizers for that object will not be
run and the native memory pointed by the earlier persistent reference
will not be freed. This can be avoided by calling
`napi_delete_reference` in addition to `napi_reference_unref` for strong/weak
references when possible. The `napi_delete_reference` must not be called for
the `node_api_reftype_strong` references because the reference is deleted
automatically after `napi_reference_unref` call sets reference count to 0.
`napi_delete_reference` in addition to `napi_reference_unref` for
`node_api_reftype_maybe_weak` references when possible. The
`napi_delete_reference` must not be called for the `node_api_reftype_strong`
references because the reference is deleted automatically after
`napi_reference_unref` call sets reference count to 0.

#### `node_api_create_reference`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental

```c
NAPI_EXTERN napi_status node_api_create_reference(napi_env env,
napi_value value,
Expand All @@ -1726,11 +1732,11 @@ NAPI_EXTERN napi_status node_api_create_reference(napi_env env,

Returns `napi_ok` if the API succeeded.

For the `node_api_reftype_strong_or_weak` `reftype` set `initial_refcount` to 0
For the `node_api_reftype_maybe_weak` `reftype` set `initial_refcount` to 0
for a weak reference, and value greater than 0 for a strong reference. It
accepts only `napi_object` values.
The `node_api_reftype_strong` ignores the `initial_refcount` and always uses 1.
It accept `napi_value` of any type.
accepts only `napi_object` or `napi_function` values.
The `node_api_reftype_strong` must have the `initial_refcount` with value
greater than 0. It accept `napi_value` of any type.

#### `napi_create_reference`

Expand Down Expand Up @@ -1763,6 +1769,8 @@ to the `Object` passed in.
added: REPLACEME
-->

> Stability: 1 - Experimental

```c
NAPI_EXTERN napi_status node_api_get_reference_type(napi_env env,
napi_ref ref,
Expand Down
27 changes: 14 additions & 13 deletions src/js_native_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,29 +317,30 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(napi_env env,
// Methods to control object lifespan

#ifdef NAPI_EXPERIMENTAL
// For node_api_reftype_strong_or_weak set initial_refcount to 0 for a weak
// For node_api_reftype_maybe_weak set initial_refcount to 0 for a weak
// reference, and value greater than 0 for a strong reference. The
// node_api_reftype_strong ignores the initial_refcount and always uses 1.
NAPI_EXTERN napi_status node_api_create_reference(napi_env env,
napi_value value,
node_api_reftype reftype,
uint32_t initial_refcount,
napi_ref* result);
// node_api_reftype_strong must have the initial_refcount >= 1.
NAPI_EXTERN napi_status NAPI_CDECL
node_api_create_reference(napi_env env,
napi_value value,
node_api_reftype reftype,
uint32_t initial_refcount,
napi_ref* result);

// Get type of the reference.
NAPI_EXTERN napi_status node_api_get_reference_type(napi_env env,
napi_ref ref,
node_api_reftype* result);
NAPI_EXTERN napi_status NAPI_CDECL node_api_get_reference_type(
napi_env env, napi_ref ref, node_api_reftype* result);
#endif

// Create node_api_reftype_strong_or_weak reference.
// Create a reference of node_api_reftype_maybe_weak type.
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
NAPI_EXTERN napi_status NAPI_CDECL
napi_create_reference(napi_env env,
napi_value value,
uint32_t initial_refcount,
napi_ref* result);

// Delete a node_api_reftype_strong_or_weak reference. The referenced value is
// Delete a node_api_reftype_maybe_weak reference. The referenced value is
// released, and may be GC'd unless there are other references to it.
// This method cannot be used with node_api_reftype_strong references.
NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(napi_env env,
Expand All @@ -353,7 +354,7 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(napi_env env,
uint32_t* result);

// Decrement the reference count, optionally returning the resulting count.
// For node_api_reftype_strong_or_weak references if the result is 0, then the
// For node_api_reftype_maybe_weak references if the result is 0, then the
// reference is now weak and the object may be GC'd at any time if there are no
// other references.
// For node_api_reftype_strong references if the result is 0, then the
Expand Down
2 changes: 1 addition & 1 deletion src/js_native_api_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ typedef struct {

#ifdef NAPI_EXPERIMENTAL
typedef enum {
node_api_reftype_strong_or_weak,
node_api_reftype_strong,
node_api_reftype_maybe_weak,
} node_api_reftype;
#endif

Expand Down
27 changes: 14 additions & 13 deletions src/js_native_api_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ class CallbackBundle {
v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
Reference::New(env,
cbdata,
node_api_reftype_strong_or_weak,
node_api_reftype_maybe_weak,
0,
true,
Delete,
Expand Down Expand Up @@ -440,7 +440,7 @@ inline napi_status Wrap(napi_env env,
CHECK_ARG(env, finalize_cb);
reference = v8impl::Reference::New(env,
obj,
node_api_reftype_strong_or_weak,
node_api_reftype_maybe_weak,
0,
false,
finalize_cb,
Expand All @@ -452,7 +452,7 @@ inline napi_status Wrap(napi_env env,
reference = v8impl::Reference::New(
env,
obj,
node_api_reftype_strong_or_weak,
node_api_reftype_maybe_weak,
0,
true,
finalize_cb,
Expand Down Expand Up @@ -593,15 +593,12 @@ Reference::Reference(napi_env env,
node_api_reftype reftype,
uint32_t initial_refcount,
Args&&... args)
: RefBase(
env,
(reftype == node_api_reftype_strong_or_weak) ? initial_refcount : 1,
std::forward<Args>(args)...),
: RefBase(env, initial_refcount, std::forward<Args>(args)...),
_persistent(env->isolate, value),
_secondPassParameter(new SecondPassCallParameterRef(this)),
_secondPassScheduled(false),
_refType(reftype) {
if (RefCount() == 0) {
if (RefCount() == 0 && _refType == node_api_reftype_maybe_weak) {
SetWeak();
}
}
Expand Down Expand Up @@ -645,7 +642,7 @@ uint32_t Reference::Unref() {
uint32_t old_refcount = RefCount();
uint32_t refcount = RefBase::Unref();
if (old_refcount == 1 && refcount == 0) {
if (_refType == node_api_reftype_strong_or_weak) {
if (_refType == node_api_reftype_maybe_weak) {
SetWeak();
} else {
Delete(this);
Expand Down Expand Up @@ -2425,7 +2422,7 @@ napi_status NAPI_CDECL napi_create_external(napi_env env,
// callback.
v8impl::Reference::New(env,
external_value,
node_api_reftype_strong_or_weak,
node_api_reftype_maybe_weak,
0,
true,
finalize_cb,
Expand Down Expand Up @@ -2519,7 +2516,7 @@ napi_status NAPI_CDECL napi_create_reference(napi_env env,
uint32_t initial_refcount,
napi_ref* result) {
return node_api_create_reference(
env, value, node_api_reftype_strong_or_weak, initial_refcount, result);
env, value, node_api_reftype_maybe_weak, initial_refcount, result);
}

napi_status node_api_create_reference(napi_env env,
Expand All @@ -2534,11 +2531,15 @@ napi_status node_api_create_reference(napi_env env,
CHECK_ARG(env, result);

v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
if (reftype == node_api_reftype_strong_or_weak) {
if (reftype == node_api_reftype_maybe_weak) {
if (!(v8_value->IsObject() || v8_value->IsFunction() ||
v8_value->IsSymbol())) {
return napi_set_last_error(env, napi_invalid_arg);
}
} else if (reftype == node_api_reftype_strong) {
if (initial_refcount == 0) {
return napi_set_last_error(env, napi_invalid_arg);
}
}
v8impl::Reference* reference = v8impl::Reference::New(
env,
Expand Down Expand Up @@ -2573,7 +2574,7 @@ napi_status NAPI_CDECL napi_delete_reference(napi_env env, napi_ref ref) {
CHECK_ARG(env, ref);

v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
if (reference->RefType() == node_api_reftype_strong_or_weak) {
if (reference->RefType() == node_api_reftype_maybe_weak) {
v8impl::Reference::Delete(reference);
} else {
return napi_set_last_error(env, napi_generic_failure);
Expand Down
6 changes: 3 additions & 3 deletions src/js_native_api_v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,10 @@ class RefBase : protected Finalizer, RefTracker {
bool _delete_self;
};

class Reference final : public RefBase {
class Reference : public RefBase {
using SecondPassCallParameterRef = Reference*;

private:
protected:
template <typename... Args>
Reference(napi_env env,
v8::Local<v8::Value> value,
Expand Down Expand Up @@ -427,7 +427,7 @@ class Reference final : public RefBase {
v8impl::Persistent<v8::Value> _persistent;
SecondPassCallParameterRef* _secondPassParameter;
bool _secondPassScheduled;
node_api_reftype _refType{node_api_reftype_strong_or_weak};
node_api_reftype _refType{node_api_reftype_strong};

FRIEND_TEST(JsNativeApiV8Test, Reference);
};
Expand Down

0 comments on commit 4f8cbed

Please sign in to comment.