• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_COMMON_H_
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_COMMON_H_
18 
19 #include "runtime/include/thread_scopes.h"
20 #include "runtime/mem/refstorage/global_object_storage.h"
21 #include "plugins/ets/runtime/interop_js/logger.h"
22 
23 #include <node_api.h>
24 
25 namespace ark::ets::interop::js {
26 
27 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
28 
29 [[noreturn]] PANDA_PUBLIC_API void InteropFatal(const char *message);
30 [[noreturn]] PANDA_PUBLIC_API void InteropFatal(const std::string &message);
31 [[noreturn]] PANDA_PUBLIC_API void InteropFatal(const char *message, napi_status status);
32 
33 // Alternative for ASSERT(!expr) with interop stacktraces, enabled in NDEBUG
34 #define INTEROP_FATAL_IF(expr)                     \
35     do {                                           \
36         bool _expr = (expr);                       \
37         if (UNLIKELY(_expr)) {                     \
38             InteropFatal("INTEROP_FATAL: " #expr); \
39             UNREACHABLE();                         \
40         }                                          \
41     } while (0)
42 
43 #ifndef NDEBUG
44 void InteropTrace(const char *func, const char *file, int line);
45 #define INTEROP_TRACE()                             \
46     do {                                            \
47         InteropTrace(__func__, __FILE__, __LINE__); \
48     } while (0)
49 #else
50 #define INTEROP_TRACE()
51 #endif
52 
53 #if !defined(NDEBUG)
54 #define NAPI_ASSERT_OK(expr) INTEROP_FATAL_IF(expr)
55 #else
56 #define NAPI_ASSERT_OK(expr) \
57     do {                     \
58         (expr);              \
59     } while (0)
60 #endif
61 
62 // Assertion for napi_* calls success, enabled in NDEBUG
63 #define NAPI_CHECK_FATAL(status)                                 \
64     do {                                                         \
65         napi_status _status = (status);                          \
66         if (UNLIKELY(_status != napi_ok)) {                      \
67             InteropFatal("NAPI_CHECK_FATAL: " #status, _status); \
68             UNREACHABLE();                                       \
69         }                                                        \
70     } while (0)
71 
72 // NOLINTEND(cppcoreguidelines-macro-usage)
73 
74 class NapiScope {
75 public:
NapiScope(napi_env env)76     explicit NapiScope(napi_env env) : env_(env)
77     {
78         [[maybe_unused]] auto status = napi_open_handle_scope(env_, &scope_);
79         ASSERT(status == napi_ok);
80     }
81 
~NapiScope()82     ~NapiScope()
83     {
84         [[maybe_unused]] auto status = napi_close_handle_scope(env_, scope_);
85         ASSERT(status == napi_ok);
86     }
87 
88     NO_COPY_SEMANTIC(NapiScope);
89     NO_MOVE_SEMANTIC(NapiScope);
90 
91 private:
92     napi_env env_ {};
93     napi_handle_scope scope_ {};
94 };
95 
96 class NapiEscapableScope {
97 public:
NapiEscapableScope(napi_env env)98     explicit NapiEscapableScope(napi_env env) : env_(env)
99     {
100         [[maybe_unused]] auto status = napi_open_escapable_handle_scope(env_, &scope_);
101         ASSERT(status == napi_ok);
102     }
103 
Escape(napi_value & val)104     void Escape(napi_value &val)
105     {
106         [[maybe_unused]] auto status = napi_escape_handle(env_, scope_, val, &val);
107         ASSERT(status == napi_ok);
108     }
109 
~NapiEscapableScope()110     ~NapiEscapableScope()
111     {
112         [[maybe_unused]] auto status = napi_close_escapable_handle_scope(env_, scope_);
113         ASSERT(status == napi_ok);
114     }
115 
116     NO_COPY_SEMANTIC(NapiEscapableScope);
117     NO_MOVE_SEMANTIC(NapiEscapableScope);
118 
119 private:
120     napi_env env_ {};
121     napi_escapable_handle_scope scope_ {};
122 };
123 
GetValueType(napi_env env,napi_value val)124 inline napi_valuetype GetValueType(napi_env env, napi_value val)
125 {
126     napi_valuetype vtype;
127     NAPI_CHECK_FATAL(napi_typeof(env, val, &vtype));
128     return vtype;
129 }
130 
GetReferenceValue(napi_env env,napi_ref ref)131 inline napi_value GetReferenceValue(napi_env env, napi_ref ref)
132 {
133     napi_value val;
134     NAPI_CHECK_FATAL(napi_get_reference_value(env, ref, &val));
135     return val;
136 }
137 
GetUndefined(napi_env env)138 inline napi_value GetUndefined(napi_env env)
139 {
140     napi_value jsValueUndefined {};
141     NAPI_CHECK_FATAL(napi_get_undefined(env, &jsValueUndefined));
142     return jsValueUndefined;
143 }
144 
GetNull(napi_env env)145 inline napi_value GetNull(napi_env env)
146 {
147     napi_value jsValueNull {};
148     NAPI_CHECK_FATAL(napi_get_null(env, &jsValueNull));
149     return jsValueNull;
150 }
151 
GetGlobal(napi_env env)152 inline napi_value GetGlobal(napi_env env)
153 {
154     napi_value jsValueGlobal {};
155     NAPI_CHECK_FATAL(napi_get_global(env, &jsValueGlobal));
156     return jsValueGlobal;
157 }
158 
IsNull(napi_env env,napi_value val)159 inline bool IsNull(napi_env env, napi_value val)
160 {
161     return GetValueType(env, val) == napi_null;
162 }
163 
IsUndefined(napi_env env,napi_value val)164 inline bool IsUndefined(napi_env env, napi_value val)
165 {
166     return GetValueType(env, val) == napi_undefined;
167 }
168 
IsNullOrUndefined(napi_env env,napi_value val)169 inline bool IsNullOrUndefined(napi_env env, napi_value val)
170 {
171     napi_valuetype vtype = GetValueType(env, val);
172     return vtype == napi_undefined || vtype == napi_null;
173 }
174 
GetString(napi_env env,napi_value jsVal)175 inline std::string GetString(napi_env env, napi_value jsVal)
176 {
177     size_t length;
178     NAPI_CHECK_FATAL(napi_get_value_string_utf8(env, jsVal, nullptr, 0, &length));
179     std::string value;
180     value.resize(length);
181     // +1 for NULL terminated string!!!
182     NAPI_CHECK_FATAL(napi_get_value_string_utf8(env, jsVal, value.data(), value.size() + 1, &length));
183     return value;
184 }
185 
NapiIsExceptionPending(napi_env env)186 inline bool NapiIsExceptionPending(napi_env env)
187 {
188     bool pending;
189     NAPI_CHECK_FATAL(napi_is_exception_pending(env, &pending));
190     return pending;
191 }
192 
NapiThrownGeneric(napi_status rc)193 inline bool NapiThrownGeneric(napi_status rc)
194 {
195     INTEROP_FATAL_IF(rc != napi_ok && rc != napi_generic_failure);
196     return rc == napi_generic_failure;
197 }
198 
NapiObjectSeal(napi_env env,napi_value jsVal)199 inline napi_status NapiObjectSeal([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value jsVal)
200 {
201 // Ark js vm crashes in napi_object_seal.
202 // Disable the call temporary
203 #ifndef PANDA_TARGET_OHOS
204     return napi_object_seal(env, jsVal);
205 #else
206     return napi_ok;
207 #endif  // PANDA_TARGET_OHOS
208 }
209 
NapiCallFunction(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv,napi_value * result)210 inline napi_status NapiCallFunction(napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv,
211                                     napi_value *result)
212 {
213 #ifdef PANDA_TARGET_OHOS
214     napi_value dummy;
215     result = result != nullptr ? result : &dummy;
216 #endif  // PANDA_TARGET_OHOS
217     return napi_call_function(env, recv, func, argc, argv, result);
218 }
219 
NapiWrap(napi_env env,napi_value jsObject,void * nativeObject,napi_finalize finalizeCb,void * finalizeHint,napi_ref * result)220 inline napi_status NapiWrap(napi_env env, napi_value jsObject, void *nativeObject, napi_finalize finalizeCb,
221                             void *finalizeHint, napi_ref *result)
222 {
223 #ifdef PANDA_TARGET_OHOS
224     napi_status status = napi_wrap(env, jsObject, nativeObject, finalizeCb, finalizeHint, nullptr);
225     if (result == nullptr || UNLIKELY(status != napi_ok)) {
226         return status;
227     }
228     return napi_create_reference(env, jsObject, 0, result);
229 #else
230     ASSERT(result == nullptr || finalizeCb != nullptr);
231     return napi_wrap(env, jsObject, nativeObject, finalizeCb, finalizeHint, result);
232 #endif
233 }
234 
235 }  // namespace ark::ets::interop::js
236 
237 #endif  // PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_COMMON_H_
238