node-api: get Node API version used by addon · nodejs/node@f489c67 · GitHub
Skip to content

Commit f489c67

Browse files
vmoroztargos
authored andcommitted
node-api: get Node API version used by addon
PR-URL: #45715 Reviewed-By: Gabriel Schulhof <gabrielschulhof@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent a4d6543 commit f489c67

17 files changed

Lines changed: 620 additions & 73 deletions

File tree

doc/api/n-api.md

Lines changed: 38 additions & 23 deletions

src/api/environment.cc

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -872,26 +872,18 @@ void AddLinkedBinding(Environment* env,
872872

873873
void AddLinkedBinding(Environment* env,
874874
const char* name,
875-
napi_addon_register_func fn) {
875+
napi_addon_register_func fn,
876+
int32_t module_api_version) {
876877
node_module mod = {
877-
-1,
878-
NM_F_LINKED,
879-
nullptr, // nm_dso_handle
880-
nullptr, // nm_filename
881-
nullptr, // nm_register_func
882-
[](v8::Local<v8::Object> exports,
883-
v8::Local<v8::Value> module,
884-
v8::Local<v8::Context> context,
885-
void* priv) {
886-
napi_module_register_by_symbol(
887-
exports,
888-
module,
889-
context,
890-
reinterpret_cast<napi_addon_register_func>(priv));
891-
},
892-
name,
893-
reinterpret_cast<void*>(fn),
894-
nullptr // nm_link
878+
-1, // nm_version for Node-API
879+
NM_F_LINKED, // nm_flags
880+
nullptr, // nm_dso_handle
881+
nullptr, // nm_filename
882+
nullptr, // nm_register_func
883+
get_node_api_context_register_func(env, name, module_api_version),
884+
name, // nm_modname
885+
reinterpret_cast<void*>(fn), // nm_priv
886+
nullptr // nm_link
895887
};
896888
AddLinkedBinding(env, mod);
897889
}

src/js_native_api_v8.cc

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,18 @@ inline napi_status Wrap(napi_env env,
457457
return GET_RETURN_STATUS(env);
458458
}
459459

460+
// In JavaScript, weak references can be created for object types (Object,
461+
// Function, and external Object) and for local symbols that are created with
462+
// the `Symbol` function call. Global symbols created with the `Symbol.for`
463+
// method cannot be weak references because they are never collected.
464+
//
465+
// Currently, V8 has no API to detect if a symbol is local or global.
466+
// Until we have a V8 API for it, we consider that all symbols can be weak.
467+
// This matches the current Node-API behavior.
468+
inline bool CanBeHeldWeakly(v8::Local<v8::Value> value) {
469+
return value->IsObject() || value->IsSymbol();
470+
}
471+
460472
} // end of anonymous namespace
461473

462474
void Finalizer::ResetFinalizer() {
@@ -551,7 +563,8 @@ void RefBase::Finalize() {
551563
template <typename... Args>
552564
Reference::Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
553565
: RefBase(env, std::forward<Args>(args)...),
554-
persistent_(env->isolate, value) {
566+
persistent_(env->isolate, value),
567+
can_be_weak_(CanBeHeldWeakly(value)) {
555568
if (RefCount() == 0) {
556569
SetWeak();
557570
}
@@ -585,7 +598,7 @@ uint32_t Reference::Ref() {
585598
return 0;
586599
}
587600
uint32_t refcount = RefBase::Ref();
588-
if (refcount == 1) {
601+
if (refcount == 1 && can_be_weak_) {
589602
persistent_.ClearWeak();
590603
}
591604
return refcount;
@@ -625,7 +638,11 @@ void Reference::Finalize() {
625638
// Mark the reference as weak and eligible for collection
626639
// by the gc.
627640
void Reference::SetWeak() {
628-
persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
641+
if (can_be_weak_) {
642+
persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
643+
} else {
644+
persistent_.Reset();
645+
}
629646
}
630647

631648
// The N-API finalizer callback may make calls into the engine. V8's heap is
@@ -2419,9 +2436,11 @@ napi_status NAPI_CDECL napi_create_reference(napi_env env,
24192436
CHECK_ARG(env, result);
24202437

24212438
v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2422-
if (!(v8_value->IsObject() || v8_value->IsFunction() ||
2423-
v8_value->IsSymbol())) {
2424-
return napi_set_last_error(env, napi_invalid_arg);
2439+
if (env->module_api_version <= 8) {
2440+
if (!(v8_value->IsObject() || v8_value->IsFunction() ||
2441+
v8_value->IsSymbol())) {
2442+
return napi_set_last_error(env, napi_invalid_arg);
2443+
}
24252444
}
24262445

24272446
v8impl::Reference* reference = v8impl::Reference::New(

src/js_native_api_v8.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@ class Finalizer;
5151
} // end of namespace v8impl
5252

5353
struct napi_env__ {
54-
explicit napi_env__(v8::Local<v8::Context> context)
55-
: isolate(context->GetIsolate()), context_persistent(isolate, context) {
54+
explicit napi_env__(v8::Local<v8::Context> context,
55+
int32_t module_api_version)
56+
: isolate(context->GetIsolate()),
57+
context_persistent(isolate, context),
58+
module_api_version(module_api_version) {
5659
napi_clear_last_error(this);
5760
}
5861

@@ -144,6 +147,7 @@ struct napi_env__ {
144147
int open_callback_scopes = 0;
145148
int refs = 1;
146149
void* instance_data = nullptr;
150+
int32_t module_api_version = NODE_API_DEFAULT_MODULE_API_VERSION;
147151

148152
protected:
149153
// Should not be deleted directly. Delete with `napi_env__::DeleteMe()`
@@ -419,6 +423,7 @@ class Reference : public RefBase {
419423
void SetWeak();
420424

421425
v8impl::Persistent<v8::Value> persistent_;
426+
bool can_be_weak_;
422427
};
423428

424429
} // end of namespace v8impl

src/node.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,9 +1237,11 @@ NODE_EXTERN void AddLinkedBinding(Environment* env,
12371237
const char* name,
12381238
addon_context_register_func fn,
12391239
void* priv);
1240-
NODE_EXTERN void AddLinkedBinding(Environment* env,
1241-
const char* name,
1242-
napi_addon_register_func fn);
1240+
NODE_EXTERN void AddLinkedBinding(
1241+
Environment* env,
1242+
const char* name,
1243+
napi_addon_register_func fn,
1244+
int32_t module_api_version = NODE_API_DEFAULT_MODULE_API_VERSION);
12431245

12441246
/* Registers a callback with the passed-in Environment instance. The callback
12451247
* is called after the event loop exits, but before the VM is disposed.

src/node_api.cc

Lines changed: 70 additions & 6 deletions

0 commit comments

Comments
 (0)