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