1 #include <node_api.h>
2 #include "../../js-native-api/common.h"
3 #include "stdlib.h"
4
5 static uint32_t finalizeCount = 0;
6
FreeData(node_api_nogc_env env,void * data,void * hint)7 static void FreeData(node_api_nogc_env env, void* data, void* hint) {
8 NODE_API_NOGC_ASSERT_RETURN_VOID(data != NULL, "Expects non-NULL data.");
9 free(data);
10 }
11
Finalize(node_api_nogc_env env,void * data,void * hint)12 static void Finalize(node_api_nogc_env env, void* data, void* hint) {
13 ++finalizeCount;
14 }
15
GetArgValue(napi_env env,napi_callback_info info,napi_value * argValue)16 static napi_status GetArgValue(napi_env env,
17 napi_callback_info info,
18 napi_value* argValue) {
19 size_t argc = 1;
20 NODE_API_CHECK_STATUS(
21 napi_get_cb_info(env, info, &argc, argValue, NULL, NULL));
22
23 NODE_API_ASSERT_STATUS(env, argc == 1, "Expects one arg.");
24 return napi_ok;
25 }
26
GetArgValueAsIndex(napi_env env,napi_callback_info info,uint32_t * index)27 static napi_status GetArgValueAsIndex(napi_env env,
28 napi_callback_info info,
29 uint32_t* index) {
30 napi_value argValue;
31 NODE_API_CHECK_STATUS(GetArgValue(env, info, &argValue));
32
33 napi_valuetype valueType;
34 NODE_API_CHECK_STATUS(napi_typeof(env, argValue, &valueType));
35 NODE_API_ASSERT_STATUS(
36 env, valueType == napi_number, "Argument must be a number.");
37
38 return napi_get_value_uint32(env, argValue, index);
39 }
40
GetRef(napi_env env,napi_callback_info info,napi_ref * ref)41 static napi_status GetRef(napi_env env,
42 napi_callback_info info,
43 napi_ref* ref) {
44 uint32_t index;
45 NODE_API_CHECK_STATUS(GetArgValueAsIndex(env, info, &index));
46
47 napi_ref* refValues;
48 NODE_API_CHECK_STATUS(napi_get_instance_data(env, (void**)&refValues));
49 NODE_API_ASSERT_STATUS(env, refValues != NULL, "Cannot get instance data.");
50
51 *ref = refValues[index];
52 return napi_ok;
53 }
54
ToUInt32Value(napi_env env,uint32_t value)55 static napi_value ToUInt32Value(napi_env env, uint32_t value) {
56 napi_value result;
57 NODE_API_CALL(env, napi_create_uint32(env, value, &result));
58 return result;
59 }
60
InitRefArray(napi_env env)61 static napi_status InitRefArray(napi_env env) {
62 // valueRefs array has one entry per napi_valuetype
63 napi_ref* valueRefs = malloc(sizeof(napi_ref) * ((int)napi_bigint + 1));
64 return napi_set_instance_data(env, valueRefs, (napi_finalize)&FreeData, NULL);
65 }
66
CreateExternal(napi_env env,napi_callback_info info)67 static napi_value CreateExternal(napi_env env, napi_callback_info info) {
68 napi_value result;
69 int* data = (int*)malloc(sizeof(int));
70 *data = 42;
71 NODE_API_CALL(env, napi_create_external(env, data, &FreeData, NULL, &result));
72 return result;
73 }
74
CreateRef(napi_env env,napi_callback_info info)75 static napi_value CreateRef(napi_env env, napi_callback_info info) {
76 napi_value argValue;
77 NODE_API_CALL(env, GetArgValue(env, info, &argValue));
78
79 napi_valuetype valueType;
80 NODE_API_CALL(env, napi_typeof(env, argValue, &valueType));
81 uint32_t index = (uint32_t)valueType;
82
83 napi_ref* valueRefs;
84 NODE_API_CALL(env, napi_get_instance_data(env, (void**)&valueRefs));
85 NODE_API_CALL(env,
86 napi_create_reference(env, argValue, 1, valueRefs + index));
87
88 return ToUInt32Value(env, index);
89 }
90
GetRefValue(napi_env env,napi_callback_info info)91 static napi_value GetRefValue(napi_env env, napi_callback_info info) {
92 napi_ref refValue;
93 NODE_API_CALL(env, GetRef(env, info, &refValue));
94 napi_value value;
95 NODE_API_CALL(env, napi_get_reference_value(env, refValue, &value));
96 return value;
97 }
98
Ref(napi_env env,napi_callback_info info)99 static napi_value Ref(napi_env env, napi_callback_info info) {
100 napi_ref refValue;
101 NODE_API_CALL(env, GetRef(env, info, &refValue));
102 uint32_t refCount;
103 NODE_API_CALL(env, napi_reference_ref(env, refValue, &refCount));
104 return ToUInt32Value(env, refCount);
105 }
106
Unref(napi_env env,napi_callback_info info)107 static napi_value Unref(napi_env env, napi_callback_info info) {
108 napi_ref refValue;
109 NODE_API_CALL(env, GetRef(env, info, &refValue));
110 uint32_t refCount;
111 NODE_API_CALL(env, napi_reference_unref(env, refValue, &refCount));
112 return ToUInt32Value(env, refCount);
113 }
114
DeleteRef(napi_env env,napi_callback_info info)115 static napi_value DeleteRef(napi_env env, napi_callback_info info) {
116 napi_ref refValue;
117 NODE_API_CALL(env, GetRef(env, info, &refValue));
118 NODE_API_CALL(env, napi_delete_reference(env, refValue));
119 return NULL;
120 }
121
AddFinalizer(napi_env env,napi_callback_info info)122 static napi_value AddFinalizer(napi_env env, napi_callback_info info) {
123 napi_value obj;
124 NODE_API_CALL(env, GetArgValue(env, info, &obj));
125
126 napi_valuetype valueType;
127 NODE_API_CALL(env, napi_typeof(env, obj, &valueType));
128 NODE_API_ASSERT(env, valueType == napi_object, "Argument must be an object.");
129
130 NODE_API_CALL(env, napi_add_finalizer(env, obj, NULL, &Finalize, NULL, NULL));
131 return NULL;
132 }
133
GetFinalizeCount(napi_env env,napi_callback_info info)134 static napi_value GetFinalizeCount(napi_env env, napi_callback_info info) {
135 return ToUInt32Value(env, finalizeCount);
136 }
137
InitFinalizeCount(napi_env env,napi_callback_info info)138 static napi_value InitFinalizeCount(napi_env env, napi_callback_info info) {
139 finalizeCount = 0;
140 return NULL;
141 }
142
143 EXTERN_C_START
144
NAPI_MODULE_INIT()145 NAPI_MODULE_INIT() {
146 finalizeCount = 0;
147 NODE_API_CALL(env, InitRefArray(env));
148
149 napi_property_descriptor properties[] = {
150 DECLARE_NODE_API_PROPERTY("createExternal", CreateExternal),
151 DECLARE_NODE_API_PROPERTY("createRef", CreateRef),
152 DECLARE_NODE_API_PROPERTY("getRefValue", GetRefValue),
153 DECLARE_NODE_API_PROPERTY("ref", Ref),
154 DECLARE_NODE_API_PROPERTY("unref", Unref),
155 DECLARE_NODE_API_PROPERTY("deleteRef", DeleteRef),
156 DECLARE_NODE_API_PROPERTY("addFinalizer", AddFinalizer),
157 DECLARE_NODE_API_PROPERTY("getFinalizeCount", GetFinalizeCount),
158 DECLARE_NODE_API_PROPERTY("initFinalizeCount", InitFinalizeCount),
159 };
160
161 NODE_API_CALL(
162 env,
163 napi_define_properties(
164 env, exports, sizeof(properties) / sizeof(*properties), properties));
165
166 return exports;
167 }
168
169 EXTERN_C_END
170