Skip to content

Commit 9c0b151

Browse files
committed
Updates for review feedback (nodejs#203)
- Add an env parameter to napi_finalize - Remove unnecessary reinterpret_cast<> calls - Remove redundant Maybe.IsNothing() checks - Make function call result parameters optional - Wrap internal field pointer values in External - Fix broken callback tests and add error-checking - Other misc test cleanup
1 parent e1ca374 commit 9c0b151

File tree

16 files changed

+198
-139
lines changed

16 files changed

+198
-139
lines changed

src/node_api.cc

Lines changed: 83 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -90,23 +90,69 @@ v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
9090
return local;
9191
}
9292

93+
// Adapter for napi_finalize callbacks.
94+
class Finalizer {
95+
protected:
96+
Finalizer(v8::Isolate* isolate,
97+
napi_finalize finalize_callback,
98+
void* finalize_data,
99+
void* finalize_hint)
100+
: _isolate(isolate),
101+
_finalize_callback(finalize_callback),
102+
_finalize_data(finalize_data),
103+
_finalize_hint(finalize_hint) {
104+
}
105+
106+
~Finalizer() {
107+
}
108+
109+
public:
110+
static Finalizer* New(v8::Isolate* isolate,
111+
napi_finalize finalize_callback = nullptr,
112+
void* finalize_data = nullptr,
113+
void* finalize_hint = nullptr) {
114+
return new Finalizer(
115+
isolate, finalize_callback, finalize_data, finalize_hint);
116+
}
117+
118+
static void Delete(Finalizer* finalizer) {
119+
delete finalizer;
120+
}
121+
122+
// node::Buffer::FreeCallback
123+
static void FinalizeBufferCallback(char* data, void* hint) {
124+
Finalizer* finalizer = static_cast<Finalizer*>(hint);
125+
if (finalizer->_finalize_callback != nullptr) {
126+
finalizer->_finalize_callback(
127+
v8impl::JsEnvFromV8Isolate(finalizer->_isolate),
128+
data,
129+
finalizer->_finalize_hint);
130+
}
131+
132+
Delete(finalizer);
133+
}
134+
135+
protected:
136+
v8::Isolate* _isolate;
137+
napi_finalize _finalize_callback;
138+
void* _finalize_data;
139+
void* _finalize_hint;
140+
};
141+
93142
// Wrapper around v8::Persistent that implements reference counting.
94-
class Reference {
143+
class Reference : private Finalizer {
95144
private:
96145
Reference(v8::Isolate* isolate,
97146
v8::Local<v8::Value> value,
98147
int initial_refcount,
99148
bool delete_self,
100-
napi_finalize finalize_callback = nullptr,
101-
void* finalize_data = nullptr,
102-
void* finalize_hint = nullptr)
103-
: _isolate(isolate),
149+
napi_finalize finalize_callback,
150+
void* finalize_data,
151+
void* finalize_hint)
152+
: Finalizer(isolate, finalize_callback, finalize_data, finalize_hint),
104153
_persistent(isolate, value),
105154
_refcount(initial_refcount),
106-
_delete_self(delete_self),
107-
_finalize_callback(finalize_callback),
108-
_finalize_data(finalize_data),
109-
_finalize_hint(finalize_hint) {
155+
_delete_self(delete_self) {
110156
if (initial_refcount == 0) {
111157
_persistent.SetWeak(
112158
this, FinalizeCallback, v8::WeakCallbackType::kParameter);
@@ -181,7 +227,9 @@ class Reference {
181227
bool delete_self = reference->_delete_self;
182228

183229
if (reference->_finalize_callback != nullptr) {
184-
reference->_finalize_callback(reference->_finalize_data,
230+
reference->_finalize_callback(
231+
v8impl::JsEnvFromV8Isolate(reference->_isolate),
232+
reference->_finalize_data,
185233
reference->_finalize_hint);
186234
}
187235

@@ -190,13 +238,9 @@ class Reference {
190238
}
191239
}
192240

193-
v8::Isolate* _isolate;
194241
v8::Persistent<v8::Value> _persistent;
195242
int _refcount;
196243
bool _delete_self;
197-
napi_finalize _finalize_callback;
198-
void* _finalize_data;
199-
void* _finalize_hint;
200244
};
201245

202246
class TryCatch : public v8::TryCatch {
@@ -419,7 +463,7 @@ v8::Local<v8::Object> CreateFunctionCallbackData(napi_env env,
419463
v8::External::New(isolate, reinterpret_cast<void*>(cb)));
420464
cbdata->SetInternalField(
421465
v8impl::kDataIndex,
422-
v8::External::New(isolate, reinterpret_cast<void*>(data)));
466+
v8::External::New(isolate, data));
423467
return cbdata;
424468
}
425469

@@ -451,7 +495,7 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
451495

452496
cbdata->SetInternalField(
453497
v8impl::kDataIndex,
454-
v8::External::New(isolate, reinterpret_cast<void*>(data)));
498+
v8::External::New(isolate, data));
455499
return cbdata;
456500
}
457501

@@ -1011,9 +1055,7 @@ napi_status napi_define_properties(napi_env env,
10111055
auto define_maybe =
10121056
obj->DefineOwnProperty(context, name, t->GetFunction(), attributes);
10131057

1014-
// IsNothing seems like a serious failure,
1015-
// should we return a different error code if the define failed?
1016-
if (define_maybe.IsNothing() || !define_maybe.FromMaybe(false)) {
1058+
if (!define_maybe.FromMaybe(false)) {
10171059
return napi_set_last_error(napi_generic_failure);
10181060
}
10191061
} else if (p->getter || p->setter) {
@@ -1422,7 +1464,6 @@ napi_status napi_call_function(napi_env env,
14221464
const napi_value* argv,
14231465
napi_value* result) {
14241466
NAPI_PREAMBLE(env);
1425-
CHECK_ARG(result);
14261467

14271468
v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(env);
14281469
v8::Local<v8::Context> context = isolate->GetCurrentContext();
@@ -1439,8 +1480,10 @@ napi_status napi_call_function(napi_env env,
14391480
if (try_catch.HasCaught()) {
14401481
return napi_set_last_error(napi_pending_exception);
14411482
} else {
1442-
CHECK_MAYBE_EMPTY(maybe, napi_generic_failure);
1443-
*result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1483+
if (result != nullptr) {
1484+
CHECK_MAYBE_EMPTY(maybe, napi_generic_failure);
1485+
*result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1486+
}
14441487
return napi_ok;
14451488
}
14461489
}
@@ -1773,7 +1816,7 @@ napi_status napi_wrap(napi_env env,
17731816
// via napi_define_class() can be (un)wrapped.
17741817
RETURN_STATUS_IF_FALSE(obj->InternalFieldCount() > 0, napi_invalid_arg);
17751818

1776-
obj->SetAlignedPointerInInternalField(0, native_object);
1819+
obj->SetInternalField(0, v8::External::New(isolate, native_object));
17771820

17781821
if (result != nullptr) {
17791822
// The returned reference should be deleted via napi_delete_reference()
@@ -1807,7 +1850,7 @@ napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) {
18071850
// via napi_define_class() can be (un)wrapped.
18081851
RETURN_STATUS_IF_FALSE(obj->InternalFieldCount() > 0, napi_invalid_arg);
18091852

1810-
*result = obj->GetAlignedPointerFromInternalField(0);
1853+
*result = v8::Local<v8::External>::Cast(obj->GetInternalField(0))->Value();
18111854

18121855
return napi_ok;
18131856
}
@@ -2124,17 +2167,20 @@ napi_status napi_make_callback(napi_env env,
21242167
const napi_value* argv,
21252168
napi_value* result) {
21262169
NAPI_PREAMBLE(env);
2127-
CHECK_ARG(result);
21282170

21292171
v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(env);
21302172
v8::Local<v8::Object> v8recv =
21312173
v8impl::V8LocalValueFromJsValue(recv).As<v8::Object>();
21322174
v8::Local<v8::Function> v8func =
21332175
v8impl::V8LocalValueFromJsValue(func).As<v8::Function>();
21342176

2135-
*result = v8impl::JsValueFromV8LocalValue(
2136-
node::MakeCallback(isolate, v8recv, v8func, argc,
2137-
reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv))));
2177+
v8::Local<v8::Value> callback_result = node::MakeCallback(
2178+
isolate, v8recv, v8func, argc,
2179+
reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2180+
2181+
if (result != nullptr) {
2182+
*result = v8impl::JsValueFromV8LocalValue(callback_result);
2183+
}
21382184

21392185
return GET_RETURN_STATUS();
21402186
}
@@ -2199,11 +2245,17 @@ napi_status napi_create_external_buffer(napi_env env,
21992245
NAPI_PREAMBLE(env);
22002246
CHECK_ARG(result);
22012247

2202-
auto maybe = node::Buffer::New(v8impl::V8IsolateFromJsEnv(env),
2248+
v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(env);
2249+
2250+
// The finalizer object will delete itself after invoking the callback.
2251+
v8impl::Finalizer* finalizer = v8impl::Finalizer::New(
2252+
isolate, finalize_cb, nullptr, finalize_hint);
2253+
2254+
auto maybe = node::Buffer::New(isolate,
22032255
static_cast<char*>(data),
22042256
length,
2205-
(node::Buffer::FreeCallback)finalize_cb,
2206-
finalize_hint);
2257+
v8impl::Finalizer::FinalizeBufferCallback,
2258+
finalizer);
22072259

22082260
CHECK_MAYBE_EMPTY(maybe, napi_generic_failure);
22092261

src/node_api_types.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ typedef struct napi_handle_scope__ *napi_handle_scope;
1717
typedef struct napi_escapable_handle_scope__ *napi_escapable_handle_scope;
1818
typedef struct napi_callback_info__ *napi_callback_info;
1919

20-
typedef void (*napi_callback)(napi_env, napi_callback_info);
21-
typedef void (*napi_finalize)(void* finalize_data, void* finalize_hint);
20+
typedef void (*napi_callback)(napi_env env,
21+
napi_callback_info info);
22+
typedef void (*napi_finalize)(napi_env env,
23+
void* finalize_data,
24+
void* finalize_hint);
2225

2326
typedef enum {
2427
napi_default = 0,

test/addons-napi/3_callbacks/binding.c

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,36 @@
11
#include <node_api.h>
22

3-
void RunCallback(napi_env env, const napi_callback_info info) {
4-
napi_status status;
5-
3+
#define NAPI_CALL(theCall) \
4+
if (theCall != napi_ok) { \
5+
const char* errorMessage = napi_get_last_error_info()->error_message; \
6+
errorMessage = errorMessage ? errorMessage : "empty error message"; \
7+
napi_throw_error((env), errorMessage); \
8+
return; \
9+
}
10+
11+
void RunCallback(napi_env env, napi_callback_info info) {
612
napi_value args[1];
7-
status = napi_get_cb_args(env, info, args, 1);
8-
if (status != napi_ok) return;
13+
NAPI_CALL(napi_get_cb_args(env, info, args, 1));
914

1015
napi_value cb = args[0];
1116

1217
napi_value argv[1];
13-
status = napi_create_string_utf8(env, "hello world", -1, argv);
14-
if (status != napi_ok) return;
18+
NAPI_CALL(napi_create_string_utf8(env, "hello world", -1, argv));
1519

1620
napi_value global;
17-
status = napi_get_global(env, &global);
18-
if (status != napi_ok) return;
21+
NAPI_CALL(napi_get_global(env, &global));
1922

20-
status = napi_call_function(env, global, cb, 1, argv, NULL);
21-
if (status != napi_ok) return;
23+
NAPI_CALL(napi_call_function(env, global, cb, 1, argv, NULL));
2224
}
2325

24-
void RunCallbackWithRecv(napi_env env, const napi_callback_info info) {
25-
napi_status status;
26-
26+
void RunCallbackWithRecv(napi_env env, napi_callback_info info) {
2727
napi_value args[2];
28-
status = napi_get_cb_args(env, info, args, 2);
29-
if (status != napi_ok) return;
28+
NAPI_CALL(napi_get_cb_args(env, info, args, 2));
3029

3130
napi_value cb = args[0];
3231
napi_value recv = args[1];
3332

34-
status = napi_call_function(env, recv, cb, 0, NULL, NULL);
35-
if (status != napi_ok) return;
33+
NAPI_CALL(napi_call_function(env, recv, cb, 0, NULL, NULL));
3634
}
3735

3836
#define DECLARE_NAPI_METHOD(name, func) \

test/addons-napi/3_callbacks/test.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,9 @@ addon.RunCallback(function(msg) {
77
assert.strictEqual(msg, 'hello world');
88
});
99

10-
const global = function() { return this; }.apply();
11-
1210
function testRecv(desiredRecv) {
1311
addon.RunCallbackWithRecv(function() {
14-
assert.strictEqual(this,
15-
(desiredRecv === undefined ||
16-
desiredRecv === null) ?
17-
global : desiredRecv);
12+
assert.strictEqual(this, desiredRecv);
1813
}, desiredRecv);
1914
}
2015

test/addons-napi/4_object_factory/binding.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <node_api.h>
22

3-
void CreateObject(napi_env env, const napi_callback_info info) {
3+
void CreateObject(napi_env env, napi_callback_info info) {
44
napi_status status;
55

66
napi_value args[1];

test/addons-napi/4_object_factory/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ const addon = require(`./build/${common.buildType}/binding`);
55

66
const obj1 = addon('hello');
77
const obj2 = addon('world');
8-
assert.strictEqual(obj1.msg + ' ' + obj2.msg, 'hello world');
8+
assert.strictEqual(`${obj1.msg} ${obj2.msg}`, 'hello world');

test/addons-napi/6_object_wrap/myobject.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ MyObject::MyObject(double value)
77

88
MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); }
99

10-
void MyObject::Destructor(void* nativeObject, void* /*finalize_hint*/) {
11-
reinterpret_cast<MyObject*>(nativeObject)->~MyObject();
10+
void MyObject::Destructor(
11+
napi_env env, void* nativeObject, void* /*finalize_hint*/) {
12+
MyObject* obj = static_cast<MyObject*>(nativeObject);
13+
delete obj;
1214
}
1315

1416
#define DECLARE_NAPI_METHOD(name, func) \
@@ -67,7 +69,7 @@ void MyObject::New(napi_env env, napi_callback_info info) {
6769
obj->env_ = env;
6870
status = napi_wrap(env,
6971
jsthis,
70-
reinterpret_cast<void*>(obj),
72+
obj,
7173
MyObject::Destructor,
7274
nullptr, // finalize_hint
7375
&obj->wrapper_);

test/addons-napi/6_object_wrap/myobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
class MyObject {
77
public:
88
static void Init(napi_env env, napi_value exports);
9-
static void Destructor(void* nativeObject, void* finalize_hint);
9+
static void Destructor(napi_env env, void* nativeObject, void* finalize_hint);
1010

1111
private:
1212
explicit MyObject(double value_ = 0);

test/addons-napi/7_factory_wrap/myobject.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {}
44

55
MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); }
66

7-
void MyObject::Destructor(void* nativeObject, void* /*finalize_hint*/) {
8-
reinterpret_cast<MyObject*>(nativeObject)->~MyObject();
7+
void MyObject::Destructor(napi_env env,
8+
void* nativeObject,
9+
void* /*finalize_hint*/) {
10+
MyObject* obj = static_cast<MyObject*>(nativeObject);
11+
delete obj;
912
}
1013

1114
#define DECLARE_NAPI_METHOD(name, func) \
@@ -57,7 +60,7 @@ void MyObject::New(napi_env env, napi_callback_info info) {
5760
obj->env_ = env;
5861
status = napi_wrap(env,
5962
jsthis,
60-
reinterpret_cast<void*>(obj),
63+
obj,
6164
MyObject::Destructor,
6265
nullptr, /* finalize_hint */
6366
&obj->wrapper_);

test/addons-napi/7_factory_wrap/myobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
class MyObject {
77
public:
88
static napi_status Init(napi_env env);
9-
static void Destructor(void* nativeObject, void* /*finalize_hint*/);
9+
static void Destructor(napi_env env, void* nativeObject, void* finalize_hint);
1010
static napi_status NewInstance(napi_env env,
1111
napi_value arg,
1212
napi_value* instance);

0 commit comments

Comments
 (0)