• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdlib.h>
2 #include <assert.h>
3 #include <js_native_api.h>
4 #include "../common.h"
5 
6 static int test_value = 1;
7 static int finalize_count = 0;
8 static napi_ref test_reference = NULL;
9 
GetFinalizeCount(napi_env env,napi_callback_info info)10 static napi_value GetFinalizeCount(napi_env env, napi_callback_info info) {
11   napi_value result;
12   NAPI_CALL(env, napi_create_int32(env, finalize_count, &result));
13   return result;
14 }
15 
FinalizeExternal(napi_env env,void * data,void * hint)16 static void FinalizeExternal(napi_env env, void* data, void* hint) {
17   int *actual_value = data;
18   NAPI_ASSERT_RETURN_VOID(env, actual_value == &test_value,
19       "The correct pointer was passed to the finalizer");
20   finalize_count++;
21 }
22 
CreateExternal(napi_env env,napi_callback_info info)23 static napi_value CreateExternal(napi_env env, napi_callback_info info) {
24   int* data = &test_value;
25 
26   napi_value result;
27   NAPI_CALL(env,
28       napi_create_external(env,
29                            data,
30                            NULL, /* finalize_cb */
31                            NULL, /* finalize_hint */
32                            &result));
33 
34   finalize_count = 0;
35   return result;
36 }
37 
CreateSymbol(napi_env env,napi_callback_info info)38 static napi_value CreateSymbol(napi_env env, napi_callback_info info) {
39 
40     size_t argc = 1;
41     napi_value args[1];
42 
43     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL,NULL));
44     NAPI_ASSERT(env, argc == 1, "Expect one argument only (symbol description)");
45 
46     napi_value result_symbol;
47 
48     NAPI_CALL(env, napi_create_symbol(env, args[0], &result_symbol));
49     return result_symbol;
50 }
51 
52 static napi_value
CreateExternalWithFinalize(napi_env env,napi_callback_info info)53 CreateExternalWithFinalize(napi_env env, napi_callback_info info) {
54   napi_value result;
55   NAPI_CALL(env,
56       napi_create_external(env,
57                            &test_value,
58                            FinalizeExternal,
59                            NULL, /* finalize_hint */
60                            &result));
61 
62   finalize_count = 0;
63   return result;
64 }
65 
CheckExternal(napi_env env,napi_callback_info info)66 static napi_value CheckExternal(napi_env env, napi_callback_info info) {
67   size_t argc = 1;
68   napi_value arg;
69   NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL));
70 
71   NAPI_ASSERT(env, argc == 1, "Expected one argument.");
72 
73   napi_valuetype argtype;
74   NAPI_CALL(env, napi_typeof(env, arg, &argtype));
75 
76   NAPI_ASSERT(env, argtype == napi_external, "Expected an external value.");
77 
78   void* data;
79   NAPI_CALL(env, napi_get_value_external(env, arg, &data));
80 
81   NAPI_ASSERT(env, data != NULL && *(int*)data == test_value,
82       "An external data value of 1 was expected.");
83 
84   return NULL;
85 }
86 
CreateReference(napi_env env,napi_callback_info info)87 static napi_value CreateReference(napi_env env, napi_callback_info info) {
88   NAPI_ASSERT(env, test_reference == NULL,
89       "The test allows only one reference at a time.");
90 
91   size_t argc = 2;
92   napi_value args[2];
93   NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
94   NAPI_ASSERT(env, argc == 2, "Expected two arguments.");
95 
96   uint32_t initial_refcount;
97   NAPI_CALL(env, napi_get_value_uint32(env, args[1], &initial_refcount));
98 
99   NAPI_CALL(env,
100       napi_create_reference(env, args[0], initial_refcount, &test_reference));
101 
102   NAPI_ASSERT(env, test_reference != NULL,
103       "A reference should have been created.");
104 
105   return NULL;
106 }
107 
DeleteReference(napi_env env,napi_callback_info info)108 static napi_value DeleteReference(napi_env env, napi_callback_info info) {
109   NAPI_ASSERT(env, test_reference != NULL,
110       "A reference must have been created.");
111 
112   NAPI_CALL(env, napi_delete_reference(env, test_reference));
113   test_reference = NULL;
114   return NULL;
115 }
116 
IncrementRefcount(napi_env env,napi_callback_info info)117 static napi_value IncrementRefcount(napi_env env, napi_callback_info info) {
118   NAPI_ASSERT(env, test_reference != NULL,
119       "A reference must have been created.");
120 
121   uint32_t refcount;
122   NAPI_CALL(env, napi_reference_ref(env, test_reference, &refcount));
123 
124   napi_value result;
125   NAPI_CALL(env, napi_create_uint32(env, refcount, &result));
126   return result;
127 }
128 
DecrementRefcount(napi_env env,napi_callback_info info)129 static napi_value DecrementRefcount(napi_env env, napi_callback_info info) {
130   NAPI_ASSERT(env, test_reference != NULL,
131       "A reference must have been created.");
132 
133   uint32_t refcount;
134   NAPI_CALL(env, napi_reference_unref(env, test_reference, &refcount));
135 
136   napi_value result;
137   NAPI_CALL(env, napi_create_uint32(env, refcount, &result));
138   return result;
139 }
140 
GetReferenceValue(napi_env env,napi_callback_info info)141 static napi_value GetReferenceValue(napi_env env, napi_callback_info info) {
142   NAPI_ASSERT(env, test_reference != NULL,
143       "A reference must have been created.");
144 
145   napi_value result;
146   NAPI_CALL(env, napi_get_reference_value(env, test_reference, &result));
147   return result;
148 }
149 
DeleteBeforeFinalizeFinalizer(napi_env env,void * finalize_data,void * finalize_hint)150 static void DeleteBeforeFinalizeFinalizer(
151     napi_env env, void* finalize_data, void* finalize_hint) {
152   napi_ref* ref = (napi_ref*)finalize_data;
153   napi_value value;
154   assert(napi_get_reference_value(env, *ref, &value) == napi_ok);
155   assert(value == NULL);
156   napi_delete_reference(env, *ref);
157   free(ref);
158 }
159 
ValidateDeleteBeforeFinalize(napi_env env,napi_callback_info info)160 static napi_value ValidateDeleteBeforeFinalize(napi_env env, napi_callback_info info) {
161   napi_value wrapObject;
162   size_t argc = 1;
163   NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &wrapObject, NULL, NULL));
164 
165   napi_ref* ref_t = malloc(sizeof(napi_ref));
166   NAPI_CALL(env, napi_wrap(env,
167                           wrapObject,
168                           ref_t,
169                           DeleteBeforeFinalizeFinalizer,
170                           NULL,
171                           NULL));
172 
173   // Create a reference that will be eligible for collection at the same
174   // time as the wrapped object by passing in the same wrapObject.
175   // This means that the FinalizeOrderValidation callback may be run
176   // before the finalizer for the newly created reference (there is a finalizer
177   // behind the scenes even though it cannot be passed to napi_create_reference)
178   // The Finalizer for the wrap (which is different than the finalizer
179   // for the reference) calls napi_delete_reference validating that
180   // napi_delete_reference can be called before the finalizer for the
181   // reference runs.
182   NAPI_CALL(env, napi_create_reference(env, wrapObject, 0, ref_t));
183   return wrapObject;
184 }
185 
186 EXTERN_C_START
Init(napi_env env,napi_value exports)187 napi_value Init(napi_env env, napi_value exports) {
188   napi_property_descriptor descriptors[] = {
189     DECLARE_NAPI_GETTER("finalizeCount", GetFinalizeCount),
190     DECLARE_NAPI_PROPERTY("createExternal", CreateExternal),
191     DECLARE_NAPI_PROPERTY("createExternalWithFinalize",
192         CreateExternalWithFinalize),
193     DECLARE_NAPI_PROPERTY("checkExternal", CheckExternal),
194     DECLARE_NAPI_PROPERTY("createReference", CreateReference),
195     DECLARE_NAPI_PROPERTY("createSymbol", CreateSymbol),
196     DECLARE_NAPI_PROPERTY("deleteReference", DeleteReference),
197     DECLARE_NAPI_PROPERTY("incrementRefcount", IncrementRefcount),
198     DECLARE_NAPI_PROPERTY("decrementRefcount", DecrementRefcount),
199     DECLARE_NAPI_GETTER("referenceValue", GetReferenceValue),
200     DECLARE_NAPI_PROPERTY("validateDeleteBeforeFinalize",
201                           ValidateDeleteBeforeFinalize),
202   };
203 
204   NAPI_CALL(env, napi_define_properties(
205       env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));
206 
207   return exports;
208 }
209 EXTERN_C_END
210