• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #include "plugins/ets/runtime/types/ets_bigint.h"
23 #include "utils/small_vector.h"
24 
25 #include <node_api.h>
26 
27 #include <functional>
28 
29 #if defined(PANDA_JS_ETS_HYBRID_MODE)
30 #include "interfaces/inner_api/napi/native_node_hybrid_api.h"
31 #else
32 // NOLINTBEGIN(readability-identifier-naming)
33 napi_status __attribute__((weak))  // CC-OFF(G.FMT.07) project code style
34 napi_wrap_with_xref(napi_env env, napi_value js_object, void *native_object, napi_finalize finalize_cb,
35                     napi_ref *result);
36 napi_status __attribute__((weak))  // CC-OFF(G.FMT.07) project code style
37 napi_xref_unwrap(napi_env env, napi_value js_object, void **result);
38 napi_status __attribute__((weak))  // CC-OFF(G.FMT.07) project code style
39 napi_create_xref(napi_env env, napi_value value, uint32_t initial_refcount, napi_ref *result);
40 napi_status __attribute__((weak))  // CC-OFF(G.FMT.07) project code style
41 napi_register_appstate_callback(napi_env env, void (*f)(int a1, int64_t a2));
42 // NOLINTEND(readability-identifier-naming)
43 #endif
44 
45 namespace ark::ets::interop::js {
46 
47 constexpr size_t BIGINT_BITS_NUM = 32;
48 constexpr size_t BIT_64 = 64;
49 
50 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
51 
52 [[noreturn]] PANDA_PUBLIC_API void InteropFatal(const char *message);
53 [[noreturn]] PANDA_PUBLIC_API void InteropFatal(const std::string &message);
54 [[noreturn]] PANDA_PUBLIC_API void InteropFatal(const char *message, napi_status status);
55 
56 std::pair<SmallVector<uint64_t, 4U>, int> GetBigInt(napi_env env, napi_value jsVal);
57 SmallVector<uint64_t, 4U> ConvertBigIntArrayFromEtsToJs(const std::vector<uint32_t> &etsArray);
58 std::vector<EtsInt> ConvertBigIntArrayFromJsToEts(SmallVector<uint64_t, 4U> &jsArray);
59 
60 PANDA_PUBLIC_API void ThrowNoInteropContextException();
61 
62 bool NapiGetProperty(napi_env env, napi_value object, napi_value key, napi_value *result);
63 bool NapiGetNamedProperty(napi_env env, napi_value object, const char *utf8name, napi_value *result);
64 
65 // Alternative for ASSERT(!expr) with interop stacktraces, enabled in NDEBUG
66 #define INTEROP_FATAL_IF(expr)                     \
67     do {                                           \
68         bool _expr = (expr);                       \
69         if (UNLIKELY(_expr)) {                     \
70             InteropFatal("INTEROP_FATAL: " #expr); \
71             UNREACHABLE();                         \
72         }                                          \
73     } while (0)
74 
75 #define INTEROP_RETURN_IF(expr) \
76     do {                        \
77         bool _expr = (expr);    \
78         if (UNLIKELY(_expr)) {  \
79             return false;       \
80         }                       \
81     } while (0)
82 
83 #ifndef NDEBUG
84 void InteropTrace(const char *func, const char *file, int line);
85 #define INTEROP_TRACE()                             \
86     do {                                            \
87         InteropTrace(__func__, __FILE__, __LINE__); \
88     } while (0)
89 #else
90 #define INTEROP_TRACE()
91 #endif
92 
93 #if !defined(NDEBUG)
94 #define NAPI_ASSERT_OK(expr) INTEROP_FATAL_IF(expr)
95 #else
96 #define NAPI_ASSERT_OK(expr) \
97     do {                     \
98         (expr);              \
99     } while (0)
100 #endif
101 
102 // Assertion for napi_* calls success, enabled in NDEBUG
103 #define NAPI_CHECK_FATAL(status)                                 \
104     do {                                                         \
105         napi_status _status = (status);                          \
106         if (UNLIKELY(_status != napi_ok)) {                      \
107             InteropFatal("NAPI_CHECK_FATAL: " #status, _status); \
108             UNREACHABLE();                                       \
109         }                                                        \
110     } while (0)
111 
112 #define NAPI_CHECK_RETURN(status)           \
113     do {                                    \
114         napi_status _status = (status);     \
115         if (UNLIKELY(_status != napi_ok)) { \
116             return false;                   \
117         }                                   \
118     } while (0)
119 
120 #define CHECK_NAPI_STATUS(jsStatus, ctx, coro, result)   \
121     do {                                                 \
122         napi_status local_status = (jsStatus);           \
123         if (local_status != napi_ok) {                   \
124             if ((ctx) != nullptr && (coro) != nullptr) { \
125                 (ctx)->ForwardJSException(coro);         \
126             }                                            \
127             (result) = false;                            \
128         }                                                \
129     } while (0)
130 
131 // NOLINTEND(cppcoreguidelines-macro-usage)
132 
133 class NapiScope {
134 public:
NapiScope(napi_env env)135     explicit NapiScope(napi_env env) : env_(env)
136     {
137         [[maybe_unused]] auto status = napi_open_handle_scope(env_, &scope_);
138         ASSERT(status == napi_ok);
139     }
140 
~NapiScope()141     ~NapiScope()
142     {
143         [[maybe_unused]] auto status = napi_close_handle_scope(env_, scope_);
144         ASSERT(status == napi_ok);
145     }
146 
147     NO_COPY_SEMANTIC(NapiScope);
148     NO_MOVE_SEMANTIC(NapiScope);
149 
150 private:
151     napi_env env_ {};
152     napi_handle_scope scope_ {};
153 };
154 
155 class NapiEscapableScope {
156 public:
NapiEscapableScope(napi_env env)157     explicit NapiEscapableScope(napi_env env) : env_(env)
158     {
159         [[maybe_unused]] auto status = napi_open_escapable_handle_scope(env_, &scope_);
160         ASSERT(status == napi_ok);
161     }
162 
Escape(napi_value & val)163     void Escape(napi_value &val)
164     {
165         [[maybe_unused]] auto status = napi_escape_handle(env_, scope_, val, &val);
166         ASSERT(status == napi_ok);
167     }
168 
~NapiEscapableScope()169     ~NapiEscapableScope()
170     {
171         [[maybe_unused]] auto status = napi_close_escapable_handle_scope(env_, scope_);
172         ASSERT(status == napi_ok);
173     }
174 
175     NO_COPY_SEMANTIC(NapiEscapableScope);
176     NO_MOVE_SEMANTIC(NapiEscapableScope);
177 
178 private:
179     napi_env env_ {};
180     napi_escapable_handle_scope scope_ {};
181 };
182 
GetValueType(napi_env env,napi_value val)183 inline napi_valuetype GetValueType(napi_env env, napi_value val)
184 {
185     napi_valuetype vtype;
186     NAPI_CHECK_FATAL(napi_typeof(env, val, &vtype));
187     return vtype;
188 }
189 
GetReferenceValue(napi_env env,napi_ref ref)190 inline napi_value GetReferenceValue(napi_env env, napi_ref ref)
191 {
192     napi_value val;
193     NAPI_CHECK_FATAL(napi_get_reference_value(env, ref, &val));
194     return val;
195 }
196 
GetUndefined(napi_env env)197 inline napi_value GetUndefined(napi_env env)
198 {
199     napi_value jsValueUndefined {};
200     NAPI_CHECK_FATAL(napi_get_undefined(env, &jsValueUndefined));
201     return jsValueUndefined;
202 }
203 
GetNull(napi_env env)204 inline napi_value GetNull(napi_env env)
205 {
206     napi_value jsValueNull {};
207     NAPI_CHECK_FATAL(napi_get_null(env, &jsValueNull));
208     return jsValueNull;
209 }
210 
GetGlobal(napi_env env)211 inline napi_value GetGlobal(napi_env env)
212 {
213     napi_value jsValueGlobal {};
214     NAPI_CHECK_FATAL(napi_get_global(env, &jsValueGlobal));
215     return jsValueGlobal;
216 }
217 
GetBooleanValue(napi_env env,bool val)218 inline napi_value GetBooleanValue(napi_env env, bool val)
219 {
220     napi_value jsValueBoolean {};
221     NAPI_CHECK_FATAL(napi_get_boolean(env, val, &jsValueBoolean));
222     return jsValueBoolean;
223 }
224 
IsNull(napi_env env,napi_value val)225 inline bool IsNull(napi_env env, napi_value val)
226 {
227     return GetValueType(env, val) == napi_null;
228 }
229 
IsUndefined(napi_env env,napi_value val)230 inline bool IsUndefined(napi_env env, napi_value val)
231 {
232     return GetValueType(env, val) == napi_undefined;
233 }
234 
IsNullOrUndefined(napi_env env,napi_value val)235 inline bool IsNullOrUndefined(napi_env env, napi_value val)
236 {
237     napi_valuetype vtype = GetValueType(env, val);
238     return vtype == napi_undefined || vtype == napi_null;
239 }
240 
GetString(napi_env env,napi_value jsVal)241 inline std::string GetString(napi_env env, napi_value jsVal)
242 {
243     size_t length;
244     NAPI_CHECK_FATAL(napi_get_value_string_utf8(env, jsVal, nullptr, 0, &length));
245     std::string value;
246     value.resize(length);
247     // +1 for NULL terminated string!!!
248     NAPI_CHECK_FATAL(napi_get_value_string_utf8(env, jsVal, value.data(), value.size() + 1, &length));
249     return value;
250 }
251 
NapiIsExceptionPending(napi_env env)252 inline bool NapiIsExceptionPending(napi_env env)
253 {
254     bool pending;
255     NAPI_CHECK_FATAL(napi_is_exception_pending(env, &pending));
256     return pending;
257 }
258 
NapiThrownGeneric(napi_status rc)259 inline bool NapiThrownGeneric(napi_status rc)
260 {
261     INTEROP_FATAL_IF(rc != napi_ok && rc != napi_generic_failure);
262     return rc == napi_generic_failure;
263 }
264 
NapiCallFunction(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv,napi_value * result)265 inline napi_status NapiCallFunction(napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv,
266                                     napi_value *result)
267 {
268 #if defined(PANDA_TARGET_OHOS) || defined(PANDA_JS_ETS_HYBRID_MODE)
269     napi_value dummy;
270     result = result != nullptr ? result : &dummy;
271 #endif  // PANDA_TARGET_OHOS
272     return napi_call_function(env, recv, func, argc, argv, result);
273 }
274 
275 }  // namespace ark::ets::interop::js
276 
277 #endif  // PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_COMMON_H_
278