Skip to content

Commit 5af645f

Browse files
author
Gabriel Schulhof
committed
src: add Addon<T> class
* separate out instance-related APIs from `ObjectWrap<T>` into a new class `InstanceWrap<T>` which then becomes a base class for `ObjectWrap<T>`. * Add `Addon<T>` class as a subclass of `InstanceWrap<T>`, reimplementing `Unwrap()` to retrieve the instance data using `GetInstanceData<T>()` of `Napi::Env` instead of `napi_unwrap()`. * Add macros `NODE_API_ADDON()` and `NODE_API_NAMED_ADDON()` to load an add-on from its `Addon<T>` subclass definition. Bindings created like this perform slightly worse than static ones in exchange for the benefit of having the context of a class instance as their C++ `this` object. This way, they avoid having to call `info.GetInstanceData<ClassName>()` in the bindings, which brings with it the risk that the wrong `ClassName` will end up in the template parameter thus resulting in a hard-to-track-down segfault. Static bindings can still be created and associated with the `exports` object and they can use `Napi::Env::GetInstanceData()` to retrieve the add-on instance. PR-URL: #749 Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
1 parent 6148fb4 commit 5af645f

File tree

14 files changed

+1312
-516
lines changed

14 files changed

+1312
-516
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ The oldest Node.js version supported by the current version of node-addon-api is
7777

7878
The following is the documentation for node-addon-api.
7979

80+
- [Addon Structure](doc/addon.md)
8081
- [Basic Types](doc/basic_types.md)
8182
- [Array](doc/basic_types.md#array)
8283
- [Symbol](doc/symbol.md)

benchmark/function_args.cc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,66 @@ static void FourArgFunction(const Napi::CallbackInfo& info) {
7878
Napi::Value argv3 = info[3]; (void) argv3;
7979
}
8080

81+
#if NAPI_VERSION > 5
82+
class FunctionArgsBenchmark : public Napi::Addon<FunctionArgsBenchmark> {
83+
public:
84+
FunctionArgsBenchmark(Napi::Env env, Napi::Object exports) {
85+
DefineAddon(exports, {
86+
InstanceValue("addon", DefineProperties(Napi::Object::New(env), {
87+
InstanceMethod("noArgFunction", &FunctionArgsBenchmark::NoArgFunction),
88+
InstanceMethod("oneArgFunction",
89+
&FunctionArgsBenchmark::OneArgFunction),
90+
InstanceMethod("twoArgFunction",
91+
&FunctionArgsBenchmark::TwoArgFunction),
92+
InstanceMethod("threeArgFunction",
93+
&FunctionArgsBenchmark::ThreeArgFunction),
94+
InstanceMethod("fourArgFunction",
95+
&FunctionArgsBenchmark::FourArgFunction),
96+
}), napi_enumerable),
97+
InstanceValue("addon_templated",
98+
DefineProperties(Napi::Object::New(env), {
99+
InstanceMethod<&FunctionArgsBenchmark::NoArgFunction>(
100+
"noArgFunction"),
101+
InstanceMethod<&FunctionArgsBenchmark::OneArgFunction>(
102+
"oneArgFunction"),
103+
InstanceMethod<&FunctionArgsBenchmark::TwoArgFunction>(
104+
"twoArgFunction"),
105+
InstanceMethod<&FunctionArgsBenchmark::ThreeArgFunction>(
106+
"threeArgFunction"),
107+
InstanceMethod<&FunctionArgsBenchmark::FourArgFunction>(
108+
"fourArgFunction"),
109+
}), napi_enumerable),
110+
});
111+
}
112+
private:
113+
void NoArgFunction(const Napi::CallbackInfo& info) {
114+
(void) info;
115+
}
116+
117+
void OneArgFunction(const Napi::CallbackInfo& info) {
118+
Napi::Value argv0 = info[0]; (void) argv0;
119+
}
120+
121+
void TwoArgFunction(const Napi::CallbackInfo& info) {
122+
Napi::Value argv0 = info[0]; (void) argv0;
123+
Napi::Value argv1 = info[1]; (void) argv1;
124+
}
125+
126+
void ThreeArgFunction(const Napi::CallbackInfo& info) {
127+
Napi::Value argv0 = info[0]; (void) argv0;
128+
Napi::Value argv1 = info[1]; (void) argv1;
129+
Napi::Value argv2 = info[2]; (void) argv2;
130+
}
131+
132+
void FourArgFunction(const Napi::CallbackInfo& info) {
133+
Napi::Value argv0 = info[0]; (void) argv0;
134+
Napi::Value argv1 = info[1]; (void) argv1;
135+
Napi::Value argv2 = info[2]; (void) argv2;
136+
Napi::Value argv3 = info[3]; (void) argv3;
137+
}
138+
};
139+
#endif // NAPI_VERSION > 5
140+
81141
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
82142
napi_value no_arg_function, one_arg_function, two_arg_function,
83143
three_arg_function, four_arg_function;
@@ -147,6 +207,10 @@ static Napi::Object Init(Napi::Env env, Napi::Object exports) {
147207
templated["fourArgFunction"] = Napi::Function::New<FourArgFunction>(env);
148208
exports["templated"] = templated;
149209

210+
#if NAPI_VERSION > 5
211+
FunctionArgsBenchmark::Init(env, exports);
212+
#endif // NAPI_VERSION > 5
213+
150214
return exports;
151215
}
152216

benchmark/function_args.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,56 @@ const addonName = path.basename(__filename, '.js');
44

55
[ addonName, addonName + '_noexcept' ]
66
.forEach((addonName) => {
7-
const rootAddon = require(`./build/Release/${addonName}`);
7+
const rootAddon = require('bindings')({
8+
bindings: addonName,
9+
module_root: __dirname
10+
});
11+
delete rootAddon.path;
812
const implems = Object.keys(rootAddon);
13+
const maxNameLength =
14+
implems.reduce((soFar, value) => Math.max(soFar, value.length), 0);
915
const anObject = {};
1016

11-
console.log(`${addonName}: `);
17+
console.log(`\n${addonName}: `);
1218

1319
console.log('no arguments:');
1420
implems.reduce((suite, implem) => {
1521
const fn = rootAddon[implem].noArgFunction;
16-
return suite.add(implem, () => fn());
22+
return suite.add(implem.padStart(maxNameLength, ' '), () => fn());
1723
}, new Benchmark.Suite)
1824
.on('cycle', (event) => console.log(String(event.target)))
1925
.run();
2026

2127
console.log('one argument:');
2228
implems.reduce((suite, implem) => {
2329
const fn = rootAddon[implem].oneArgFunction;
24-
return suite.add(implem, () => fn('x'));
30+
return suite.add(implem.padStart(maxNameLength, ' '), () => fn('x'));
2531
}, new Benchmark.Suite)
2632
.on('cycle', (event) => console.log(String(event.target)))
2733
.run();
2834

2935
console.log('two arguments:');
3036
implems.reduce((suite, implem) => {
3137
const fn = rootAddon[implem].twoArgFunction;
32-
return suite.add(implem, () => fn('x', 12));
38+
return suite.add(implem.padStart(maxNameLength, ' '), () => fn('x', 12));
3339
}, new Benchmark.Suite)
3440
.on('cycle', (event) => console.log(String(event.target)))
3541
.run();
3642

3743
console.log('three arguments:');
3844
implems.reduce((suite, implem) => {
3945
const fn = rootAddon[implem].threeArgFunction;
40-
return suite.add(implem, () => fn('x', 12, true));
46+
return suite.add(implem.padStart(maxNameLength, ' '),
47+
() => fn('x', 12, true));
4148
}, new Benchmark.Suite)
4249
.on('cycle', (event) => console.log(String(event.target)))
4350
.run();
4451

4552
console.log('four arguments:');
4653
implems.reduce((suite, implem) => {
4754
const fn = rootAddon[implem].fourArgFunction;
48-
return suite.add(implem, () => fn('x', 12, true, anObject));
55+
return suite.add(implem.padStart(maxNameLength, ' '),
56+
() => fn('x', 12, true, anObject));
4957
}, new Benchmark.Suite)
5058
.on('cycle', (event) => console.log(String(event.target)))
5159
.run();

benchmark/property_descriptor.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ static void Setter(const Napi::CallbackInfo& info) {
2626
(void) info[0];
2727
}
2828

29+
#if NAPI_VERSION > 5
30+
class PropDescBenchmark : public Napi::Addon<PropDescBenchmark> {
31+
public:
32+
PropDescBenchmark(Napi::Env, Napi::Object exports) {
33+
DefineAddon(exports, {
34+
InstanceAccessor("addon",
35+
&PropDescBenchmark::Getter,
36+
&PropDescBenchmark::Setter,
37+
napi_enumerable),
38+
InstanceAccessor<&PropDescBenchmark::Getter,
39+
&PropDescBenchmark::Setter>("addon_templated",
40+
napi_enumerable),
41+
});
42+
}
43+
44+
private:
45+
Napi::Value Getter(const Napi::CallbackInfo& info) {
46+
return Napi::Number::New(info.Env(), 42);
47+
}
48+
49+
void Setter(const Napi::CallbackInfo& info, const Napi::Value& val) {
50+
(void) info[0];
51+
(void) val;
52+
}
53+
};
54+
#endif // NAPI_VERSION > 5
55+
2956
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
3057
napi_status status;
3158
napi_property_descriptor core_prop = {
@@ -54,6 +81,10 @@ static Napi::Object Init(Napi::Env env, Napi::Object exports) {
5481
Napi::PropertyDescriptor::Accessor<Getter, Setter>("templated",
5582
napi_enumerable));
5683

84+
#if NAPI_VERSION > 5
85+
PropDescBenchmark::Init(env, exports);
86+
#endif // NAPI_VERSION > 5
87+
5788
return exports;
5889
}
5990

benchmark/property_descriptor.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ const addonName = path.basename(__filename, '.js');
44

55
[ addonName, addonName + '_noexcept' ]
66
.forEach((addonName) => {
7-
const rootAddon = require(`./build/Release/${addonName}`);
7+
const rootAddon = require('bindings')({
8+
bindings: addonName,
9+
module_root: __dirname
10+
});
11+
delete rootAddon.path;
812
const getters = new Benchmark.Suite;
913
const setters = new Benchmark.Suite;
14+
const maxNameLength = Object.keys(rootAddon)
15+
.reduce((soFar, value) => Math.max(soFar, value.length), 0);
1016

11-
console.log(`${addonName}: `);
17+
console.log(`\n${addonName}: `);
1218

1319
Object.keys(rootAddon).forEach((key) => {
14-
getters.add(`${key} getter`, () => {
20+
getters.add(`${key} getter`.padStart(maxNameLength + 7), () => {
1521
const x = rootAddon[key];
1622
});
17-
setters.add(`${key} setter`, () => {
23+
setters.add(`${key} setter`.padStart(maxNameLength + 7), () => {
1824
rootAddon[key] = 5;
1925
})
2026
});
@@ -23,6 +29,8 @@ const addonName = path.basename(__filename, '.js');
2329
.on('cycle', (event) => console.log(String(event.target)))
2430
.run();
2531

32+
console.log('');
33+
2634
setters
2735
.on('cycle', (event) => console.log(String(event.target)))
2836
.run();

0 commit comments

Comments
 (0)