• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <js_native_api.h>
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "../common.h"
7 #include "../entry_point.h"
8 
9 typedef struct {
10   int32_t finalize_count;
11   napi_ref js_func;
12 } FinalizerData;
13 
finalizerOnlyCallback(node_api_nogc_env env,void * finalize_data,void * finalize_hint)14 static void finalizerOnlyCallback(node_api_nogc_env env,
15                                   void* finalize_data,
16                                   void* finalize_hint) {
17   FinalizerData* data = (FinalizerData*)finalize_data;
18   int32_t count = ++data->finalize_count;
19 
20   // It is safe to access instance data
21   NODE_API_NOGC_CALL_RETURN_VOID(env,
22                                  napi_get_instance_data(env, (void**)&data));
23   NODE_API_NOGC_ASSERT_RETURN_VOID(count = data->finalize_count,
24                                    "Expected to be the same FinalizerData");
25 }
26 
finalizerCallingJSCallback(napi_env env,void * finalize_data,void * finalize_hint)27 static void finalizerCallingJSCallback(napi_env env,
28                                        void* finalize_data,
29                                        void* finalize_hint) {
30   napi_value js_func, undefined;
31   FinalizerData* data = (FinalizerData*)finalize_data;
32   NODE_API_CALL_RETURN_VOID(
33       env, napi_get_reference_value(env, data->js_func, &js_func));
34   NODE_API_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
35   NODE_API_CALL_RETURN_VOID(
36       env, napi_call_function(env, undefined, js_func, 0, NULL, NULL));
37   NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, data->js_func));
38   data->js_func = NULL;
39   ++data->finalize_count;
40 }
41 
42 // Schedule async finalizer to run JavaScript-touching code.
finalizerWithJSCallback(node_api_nogc_env env,void * finalize_data,void * finalize_hint)43 static void finalizerWithJSCallback(node_api_nogc_env env,
44                                     void* finalize_data,
45                                     void* finalize_hint) {
46   NODE_API_NOGC_CALL_RETURN_VOID(
47       env,
48       node_api_post_finalizer(
49           env, finalizerCallingJSCallback, finalize_data, finalize_hint));
50 }
51 
finalizerWithFailedJSCallback(node_api_nogc_env nogc_env,void * finalize_data,void * finalize_hint)52 static void finalizerWithFailedJSCallback(node_api_nogc_env nogc_env,
53                                           void* finalize_data,
54                                           void* finalize_hint) {
55   // Intentionally cast to a napi_env to test the fatal failure.
56   napi_env env = (napi_env)nogc_env;
57   napi_value obj;
58   FinalizerData* data = (FinalizerData*)finalize_data;
59   ++data->finalize_count;
60   NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &obj));
61 }
62 
addFinalizer(napi_env env,napi_callback_info info)63 static napi_value addFinalizer(napi_env env, napi_callback_info info) {
64   size_t argc = 1;
65   napi_value argv[1] = {0};
66   FinalizerData* data;
67 
68   NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
69   NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data));
70   NODE_API_CALL(env,
71                 napi_add_finalizer(
72                     env, argv[0], data, finalizerOnlyCallback, NULL, NULL));
73   return NULL;
74 }
75 
76 // This finalizer is going to call JavaScript from finalizer and succeed.
addFinalizerWithJS(napi_env env,napi_callback_info info)77 static napi_value addFinalizerWithJS(napi_env env, napi_callback_info info) {
78   size_t argc = 2;
79   napi_value argv[2] = {0};
80   napi_valuetype arg_type;
81   FinalizerData* data;
82 
83   NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
84   NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data));
85   NODE_API_CALL(env, napi_typeof(env, argv[1], &arg_type));
86   NODE_API_ASSERT(
87       env, arg_type == napi_function, "Expected function as the second arg");
88   NODE_API_CALL(env, napi_create_reference(env, argv[1], 1, &data->js_func));
89   NODE_API_CALL(env,
90                 napi_add_finalizer(
91                     env, argv[0], data, finalizerWithJSCallback, NULL, NULL));
92   return NULL;
93 }
94 
95 // This finalizer is going to call JavaScript from finalizer and fail.
addFinalizerFailOnJS(napi_env env,napi_callback_info info)96 static napi_value addFinalizerFailOnJS(napi_env env, napi_callback_info info) {
97   size_t argc = 1;
98   napi_value argv[1] = {0};
99   FinalizerData* data;
100 
101   NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
102   NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data));
103   NODE_API_CALL(
104       env,
105       napi_add_finalizer(
106           env, argv[0], data, finalizerWithFailedJSCallback, NULL, NULL));
107   return NULL;
108 }
109 
getFinalizerCallCount(napi_env env,napi_callback_info info)110 static napi_value getFinalizerCallCount(napi_env env, napi_callback_info info) {
111   size_t argc = 1;
112   napi_value argv[1];
113   FinalizerData* data;
114   napi_value result;
115 
116   NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
117   NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data));
118   NODE_API_CALL(env, napi_create_int32(env, data->finalize_count, &result));
119   return result;
120 }
121 
finalizeData(napi_env env,void * data,void * hint)122 static void finalizeData(napi_env env, void* data, void* hint) {
123   free(data);
124 }
125 
126 EXTERN_C_START
Init(napi_env env,napi_value exports)127 napi_value Init(napi_env env, napi_value exports) {
128   FinalizerData* data = (FinalizerData*)malloc(sizeof(FinalizerData));
129   NODE_API_ASSERT(env, data != NULL, "Failed to allocate memory");
130   memset(data, 0, sizeof(FinalizerData));
131   NODE_API_CALL(env, napi_set_instance_data(env, data, finalizeData, NULL));
132   napi_property_descriptor descriptors[] = {
133       DECLARE_NODE_API_PROPERTY("addFinalizer", addFinalizer),
134       DECLARE_NODE_API_PROPERTY("addFinalizerWithJS", addFinalizerWithJS),
135       DECLARE_NODE_API_PROPERTY("addFinalizerFailOnJS", addFinalizerFailOnJS),
136       DECLARE_NODE_API_PROPERTY("getFinalizerCallCount",
137                                 getFinalizerCallCount)};
138 
139   NODE_API_CALL(
140       env,
141       napi_define_properties(env,
142                              exports,
143                              sizeof(descriptors) / sizeof(*descriptors),
144                              descriptors));
145 
146   return exports;
147 }
148 EXTERN_C_END
149