1#include <js_native_api.h>
2#include "../common.h"
3#include "../entry_point.h"
4
5static napi_value TestCreateFunctionParameters(napi_env env,
6                                               napi_callback_info info) {
7  napi_status status;
8  napi_value result, return_value;
9
10  NODE_API_CALL(env, napi_create_object(env, &return_value));
11
12  status = napi_create_function(NULL,
13                                "TrackedFunction",
14                                NAPI_AUTO_LENGTH,
15                                TestCreateFunctionParameters,
16                                NULL,
17                                &result);
18
19  add_returned_status(env,
20                      "envIsNull",
21                      return_value,
22                      "Invalid argument",
23                      napi_invalid_arg,
24                      status);
25
26  napi_create_function(env,
27                       NULL,
28                       NAPI_AUTO_LENGTH,
29                       TestCreateFunctionParameters,
30                       NULL,
31                       &result);
32
33  add_last_status(env, "nameIsNull", return_value);
34
35  napi_create_function(env,
36                       "TrackedFunction",
37                       NAPI_AUTO_LENGTH,
38                       NULL,
39                       NULL,
40                       &result);
41
42  add_last_status(env, "cbIsNull", return_value);
43
44  napi_create_function(env,
45                       "TrackedFunction",
46                       NAPI_AUTO_LENGTH,
47                       TestCreateFunctionParameters,
48                       NULL,
49                       NULL);
50
51  add_last_status(env, "resultIsNull", return_value);
52
53  return return_value;
54}
55
56static napi_value TestCallFunction(napi_env env, napi_callback_info info) {
57  size_t argc = 10;
58  napi_value args[10];
59  NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
60
61  NODE_API_ASSERT(env, argc > 0, "Wrong number of arguments");
62
63  napi_valuetype valuetype0;
64  NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype0));
65
66  NODE_API_ASSERT(env, valuetype0 == napi_function,
67      "Wrong type of arguments. Expects a function as first argument.");
68
69  napi_value* argv = args + 1;
70  argc = argc - 1;
71
72  napi_value global;
73  NODE_API_CALL(env, napi_get_global(env, &global));
74
75  napi_value result;
76  NODE_API_CALL(env, napi_call_function(env, global, args[0], argc, argv, &result));
77
78  return result;
79}
80
81static napi_value TestFunctionName(napi_env env, napi_callback_info info) {
82  return NULL;
83}
84
85static void finalize_function(napi_env env, void* data, void* hint) {
86  napi_ref ref = data;
87
88  // Retrieve the JavaScript undefined value.
89  napi_value undefined;
90  NODE_API_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
91
92  // Retrieve the JavaScript function we must call.
93  napi_value js_function;
94  NODE_API_CALL_RETURN_VOID(env, napi_get_reference_value(env, ref, &js_function));
95
96  // Call the JavaScript function to indicate that the generated JavaScript
97  // function is about to be gc-ed.
98  NODE_API_CALL_RETURN_VOID(env,
99      napi_call_function(env, undefined, js_function, 0, NULL, NULL));
100
101  // Destroy the persistent reference to the function we just called so as to
102  // properly clean up.
103  NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, ref));
104}
105
106static napi_value MakeTrackedFunction(napi_env env, napi_callback_info info) {
107  size_t argc = 1;
108  napi_value js_finalize_cb;
109  napi_valuetype arg_type;
110
111  // Retrieve and validate from the arguments the function we will use to
112  // indicate to JavaScript that the function we are about to create is about to
113  // be gc-ed.
114  NODE_API_CALL(env,
115      napi_get_cb_info(env, info, &argc, &js_finalize_cb, NULL, NULL));
116  NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments");
117  NODE_API_CALL(env, napi_typeof(env, js_finalize_cb, &arg_type));
118  NODE_API_ASSERT(env, arg_type == napi_function, "Argument must be a function");
119
120  // Dynamically create a function.
121  napi_value result;
122  NODE_API_CALL(env,
123      napi_create_function(
124          env, "TrackedFunction", NAPI_AUTO_LENGTH, TestFunctionName, NULL,
125          &result));
126
127  // Create a strong reference to the function we will call when the tracked
128  // function is about to be gc-ed.
129  napi_ref js_finalize_cb_ref;
130  NODE_API_CALL(env,
131      napi_create_reference(env, js_finalize_cb, 1, &js_finalize_cb_ref));
132
133  // Attach a finalizer to the dynamically created function and pass it the
134  // strong reference we created in the previous step.
135  NODE_API_CALL(env,
136      napi_wrap(
137          env, result, js_finalize_cb_ref, finalize_function, NULL, NULL));
138
139  return result;
140}
141
142static napi_value TestBadReturnExceptionPending(napi_env env, napi_callback_info info) {
143  napi_throw_error(env, "throwing exception", "throwing exception");
144
145  // addons should only ever return a valid napi_value even if an
146  // exception occurs, but we have seen that the C++ wrapper
147  // with exceptions enabled sometimes returns an invalid value
148  // when an exception is thrown. Test that we ignore the return
149  // value then an exeption is pending. We use 0xFFFFFFFF as a value
150  // that should never be a valid napi_value and node seems to
151  // crash if it is not ignored indicating that it is indeed invalid.
152  return (napi_value)(0xFFFFFFFFF);
153}
154
155EXTERN_C_START
156napi_value Init(napi_env env, napi_value exports) {
157  napi_value fn1;
158  NODE_API_CALL(env, napi_create_function(
159      env, NULL, NAPI_AUTO_LENGTH, TestCallFunction, NULL, &fn1));
160
161  napi_value fn2;
162  NODE_API_CALL(env, napi_create_function(
163      env, "Name", NAPI_AUTO_LENGTH, TestFunctionName, NULL, &fn2));
164
165  napi_value fn3;
166  NODE_API_CALL(env, napi_create_function(
167      env, "Name_extra", 5, TestFunctionName, NULL, &fn3));
168
169  napi_value fn4;
170  NODE_API_CALL(env,
171      napi_create_function(
172          env, "MakeTrackedFunction", NAPI_AUTO_LENGTH, MakeTrackedFunction,
173          NULL, &fn4));
174
175  napi_value fn5;
176  NODE_API_CALL(env,
177      napi_create_function(
178          env, "TestCreateFunctionParameters", NAPI_AUTO_LENGTH,
179          TestCreateFunctionParameters, NULL, &fn5));
180
181  napi_value fn6;
182  NODE_API_CALL(env,
183      napi_create_function(
184          env, "TestBadReturnExceptionPending", NAPI_AUTO_LENGTH,
185          TestBadReturnExceptionPending, NULL, &fn6));
186
187  NODE_API_CALL(env, napi_set_named_property(env, exports, "TestCall", fn1));
188  NODE_API_CALL(env, napi_set_named_property(env, exports, "TestName", fn2));
189  NODE_API_CALL(env,
190      napi_set_named_property(env, exports, "TestNameShort", fn3));
191  NODE_API_CALL(env,
192      napi_set_named_property(env, exports, "MakeTrackedFunction", fn4));
193
194  NODE_API_CALL(env,
195      napi_set_named_property(
196          env, exports, "TestCreateFunctionParameters", fn5));
197
198  NODE_API_CALL(env,
199      napi_set_named_property(
200          env, exports, "TestBadReturnExceptionPending", fn6));
201
202  return exports;
203}
204EXTERN_C_END
205