1#ifndef JS_NATIVE_API_COMMON_H_
2#define JS_NATIVE_API_COMMON_H_
3
4#include <js_native_api.h>
5#include <stdlib.h>  // abort()
6
7// Empty value so that macros here are able to return NULL or void
8#define NODE_API_RETVAL_NOTHING  // Intentionally blank #define
9
10#define GET_AND_THROW_LAST_ERROR(env)                                    \
11  do {                                                                   \
12    const napi_extended_error_info *error_info;                          \
13    napi_get_last_error_info((env), &error_info);                        \
14    bool is_pending;                                                     \
15    const char* err_message = error_info->error_message;                  \
16    napi_is_exception_pending((env), &is_pending);                       \
17    /* If an exception is already pending, don't rethrow it */           \
18    if (!is_pending) {                                                   \
19      const char* error_message = err_message != NULL ?                  \
20                       err_message :                                     \
21                      "empty error message";                             \
22      napi_throw_error((env), NULL, error_message);                      \
23    }                                                                    \
24  } while (0)
25
26// The nogc version of GET_AND_THROW_LAST_ERROR. We cannot access any
27// exceptions and we cannot fail by way of JS exception, so we abort.
28#define FATALLY_FAIL_WITH_LAST_ERROR(env)                                      \
29  do {                                                                         \
30    const napi_extended_error_info* error_info;                                \
31    napi_get_last_error_info((env), &error_info);                              \
32    const char* err_message = error_info->error_message;                       \
33    const char* error_message =                                                \
34        err_message != NULL ? err_message : "empty error message";             \
35    fprintf(stderr, "%s\n", error_message);                                    \
36    abort();                                                                   \
37  } while (0)
38
39#define NODE_API_ASSERT_BASE(env, assertion, message, ret_val)           \
40  do {                                                                   \
41    if (!(assertion)) {                                                  \
42      napi_throw_error(                                                  \
43          (env),                                                         \
44        NULL,                                                            \
45          "assertion (" #assertion ") failed: " message);                \
46      return ret_val;                                                    \
47    }                                                                    \
48  } while (0)
49
50#define NODE_API_NOGC_ASSERT_BASE(assertion, message, ret_val)                 \
51  do {                                                                         \
52    if (!(assertion)) {                                                        \
53      fprintf(stderr, "assertion (" #assertion ") failed: " message);          \
54      abort();                                                                 \
55      return ret_val;                                                          \
56    }                                                                          \
57  } while (0)
58
59// Returns NULL on failed assertion.
60// This is meant to be used inside napi_callback methods.
61#define NODE_API_ASSERT(env, assertion, message)                         \
62  NODE_API_ASSERT_BASE(env, assertion, message, NULL)
63
64// Returns empty on failed assertion.
65// This is meant to be used inside functions with void return type.
66#define NODE_API_ASSERT_RETURN_VOID(env, assertion, message)             \
67  NODE_API_ASSERT_BASE(env, assertion, message, NODE_API_RETVAL_NOTHING)
68
69#define NODE_API_NOGC_ASSERT_RETURN_VOID(assertion, message)                   \
70  NODE_API_NOGC_ASSERT_BASE(assertion, message, NODE_API_RETVAL_NOTHING)
71
72#define NODE_API_CALL_BASE(env, the_call, ret_val)                       \
73  do {                                                                   \
74    if ((the_call) != napi_ok) {                                         \
75      GET_AND_THROW_LAST_ERROR((env));                                   \
76      return ret_val;                                                    \
77    }                                                                    \
78  } while (0)
79
80#define NODE_API_NOGC_CALL_BASE(env, the_call, ret_val)                        \
81  do {                                                                         \
82    if ((the_call) != napi_ok) {                                               \
83      FATALLY_FAIL_WITH_LAST_ERROR((env));                                     \
84      return ret_val;                                                          \
85    }                                                                          \
86  } while (0)
87
88// Returns NULL if the_call doesn't return napi_ok.
89#define NODE_API_CALL(env, the_call)                                     \
90  NODE_API_CALL_BASE(env, the_call, NULL)
91
92// Returns empty if the_call doesn't return napi_ok.
93#define NODE_API_CALL_RETURN_VOID(env, the_call)                         \
94  NODE_API_CALL_BASE(env, the_call, NODE_API_RETVAL_NOTHING)
95
96#define NODE_API_NOGC_CALL_RETURN_VOID(env, the_call)                          \
97  NODE_API_NOGC_CALL_BASE(env, the_call, NODE_API_RETVAL_NOTHING)
98
99#define NODE_API_CHECK_STATUS(the_call)                                   \
100  do {                                                                         \
101    napi_status status = (the_call);                                           \
102    if (status != napi_ok) {                                                   \
103      return status;                                                           \
104    }                                                                          \
105  } while (0)
106
107#define NODE_API_ASSERT_STATUS(env, assertion, message)                        \
108  NODE_API_ASSERT_BASE(env, assertion, message, napi_generic_failure)
109
110#define DECLARE_NODE_API_PROPERTY(name, func)                            \
111  { (name), NULL, (func), NULL, NULL, NULL, napi_default, NULL }
112
113#define DECLARE_NODE_API_GETTER(name, func)                              \
114  { (name), NULL, NULL, (func), NULL, NULL, napi_default, NULL }
115
116#define DECLARE_NODE_API_PROPERTY_VALUE(name, value)                     \
117  { (name), NULL, NULL, NULL, NULL, (value), napi_default, NULL }
118
119static inline void add_returned_status(napi_env env,
120                                       const char* key,
121                                       napi_value object,
122                                       char* expected_message,
123                                       napi_status expected_status,
124                                       napi_status actual_status);
125
126static inline void add_last_status(napi_env env,
127                                   const char* key,
128                                   napi_value return_value);
129
130#include "common-inl.h"
131
132#endif  // JS_NATIVE_API_COMMON_H_
133