• 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_JS_CONVERT_BASE_H
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_BASE_H
18 
19 #include "plugins/ets/runtime/ets_panda_file_items.h"
20 #include "plugins/ets/runtime/interop_js/interop_common.h"
21 #include "plugins/ets/runtime/interop_js/js_value.h"
22 #include "runtime/handle_scope-inl.h"
23 #include "runtime/include/coretypes/class.h"
24 #include "plugins/ets/runtime/types/ets_array.h"
25 #include "plugins/ets/runtime/types/ets_arraybuffer.h"
26 #include "plugins/ets/runtime/types/ets_string.h"
27 #include "plugins/ets/runtime/types/ets_bigint.h"
28 #include "plugins/ets/runtime/types/ets_promise.h"
29 #include "plugins/ets/runtime/types/ets_promise_ref.h"
30 #include "plugins/ets/runtime/types/ets_box_primitive-inl.h"
31 #include "plugins/ets/runtime/types/ets_method.h"
32 
33 namespace ark::ets::interop::js {
34 
35 static constexpr const char *CONSTRUCTOR_NAME_BOOLEAN = "Boolean";
36 static constexpr const char *CONSTRUCTOR_NAME_NUMBER = "Number";
37 static constexpr const char *CONSTRUCTOR_NAME_STRING = "String";
38 
39 template <typename T>
AsEtsObject(T * obj)40 inline EtsObject *AsEtsObject(T *obj)
41 {
42     static_assert(std::is_base_of_v<ObjectHeader, T>);
43     return reinterpret_cast<EtsObject *>(obj);
44 }
45 
46 template <typename T>
FromEtsObject(EtsObject * obj)47 inline T *FromEtsObject(EtsObject *obj)
48 {
49     static_assert(std::is_base_of_v<ObjectHeader, T>);
50     return reinterpret_cast<T *>(obj);
51 }
52 
53 void JSConvertTypeCheckFailed(const char *typeName);
JSConvertTypeCheckFailed(const std::string & s)54 inline void JSConvertTypeCheckFailed(const std::string &s)
55 {
56     JSConvertTypeCheckFailed(s.c_str());
57 }
58 
IsConstructor(napi_env & env,napi_value & jsValue,const char * constructorName)59 static bool IsConstructor(napi_env &env, napi_value &jsValue, const char *constructorName)
60 {
61     napi_value constructor;
62     bool isInstanceof;
63     NAPI_CHECK_FATAL(napi_get_named_property(env, GetGlobal(env), constructorName, &constructor));
64     NAPI_CHECK_FATAL(napi_instanceof(env, jsValue, constructor, &isInstanceof));
65     return isInstanceof;
66 }
67 
GetValueByValueOf(napi_env env,napi_value & jsValue,const char * constructorName,napi_value * result)68 static bool GetValueByValueOf(napi_env env, napi_value &jsValue, const char *constructorName, napi_value *result)
69 {
70     if (!IsConstructor(env, jsValue, constructorName)) {
71         return false;
72     }
73     napi_value method;
74     NAPI_CHECK_FATAL(napi_get_named_property(env, jsValue, "valueOf", &method));
75     NAPI_CHECK_FATAL(napi_call_function(env, jsValue, method, 0, nullptr, result));
76     return true;
77 }
78 
79 // Base mixin class of JSConvert interface
80 // Represents primitive types and some built-in classes, has no state
81 template <typename Impl, typename ImplCpptype>
82 struct JSConvertBase {
83     JSConvertBase() = delete;
84     using cpptype = ImplCpptype;
85     static constexpr bool IS_REFTYPE = std::is_pointer_v<cpptype>;
86     static constexpr bool IS_JSVALUE = std::is_same_v<JSValue *, cpptype>;
87     static constexpr size_t TYPE_SIZE = IS_REFTYPE ? ClassHelper::OBJECT_POINTER_SIZE : sizeof(cpptype);
88 
TypeCheckFailedJSConvertBase89     static void TypeCheckFailed()
90     {
91         JSConvertTypeCheckFailed(Impl::TYPE_NAME);
92     }
93 
94     // Convert ets->js, returns nullptr if failed, throws JS exceptions
WrapJSConvertBase95     static napi_value Wrap(napi_env env, cpptype etsVal)
96     {
97         if constexpr (IS_REFTYPE) {
98             ASSERT(etsVal != nullptr);
99         }
100         auto res = Impl::WrapImpl(env, etsVal);
101         ASSERT(res != nullptr || InteropCtx::SanityJSExceptionPending());
102         return res;
103     }
104 
105     // Convert js->ets, returns nullopt if failed, throws ETS/JS exceptions
UnwrapJSConvertBase106     static std::optional<cpptype> Unwrap(InteropCtx *ctx, napi_env env, napi_value jsVal)
107     {
108         if constexpr (IS_REFTYPE) {
109             ASSERT(!IsUndefined(env, jsVal));
110         }
111         auto res = Impl::UnwrapImpl(ctx, env, jsVal);
112         ASSERT(res.has_value() || InteropCtx::SanityJSExceptionPending() || InteropCtx::SanityETSExceptionPending());
113         return res;
114     }
115 
WrapWithNullCheckJSConvertBase116     static napi_value WrapWithNullCheck(napi_env env, cpptype etsVal)
117     {
118         if constexpr (IS_REFTYPE) {
119             if (UNLIKELY(etsVal == nullptr)) {
120                 return GetUndefined(env);
121             }
122         }
123         auto res = Impl::WrapImpl(env, etsVal);
124         ASSERT(res != nullptr || InteropCtx::SanityJSExceptionPending());
125         return res;
126     }
127 
UnwrapWithNullCheckJSConvertBase128     static std::optional<cpptype> UnwrapWithNullCheck(InteropCtx *ctx, napi_env env, napi_value jsVal)
129     {
130         if constexpr (IS_REFTYPE) {
131             // NOTE(kprokopenko) can't assign null to EtsString *, hence fallback into UnwrapImpl
132             if (UNLIKELY(IsUndefined(env, jsVal))) {
133                 if constexpr (IS_JSVALUE) {
134                     return JSValue::CreateUndefined(EtsCoroutine::GetCurrent(), ctx);
135                 }
136                 return nullptr;
137             }
138         }
139         auto res = Impl::UnwrapImpl(ctx, env, jsVal);
140         ASSERT(res.has_value() || InteropCtx::SanityJSExceptionPending() || InteropCtx::SanityETSExceptionPending());
141         return res;
142     }
143 };
144 
145 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
146 #define JSCONVERT_DEFINE_TYPE(type, cpptype_)                                                                \
147     struct JSConvert##type : public JSConvertBase<JSConvert##type, cpptype_> {                               \
148         static constexpr const char *TYPE_NAME = #type;                                                      \
149         /* Must not fail */                                                                                  \
150         [[maybe_unused]] static inline napi_value WrapImpl([[maybe_unused]] napi_env env,                    \
151                                                            [[maybe_unused]] cpptype etsVal);                 \
152         /* May fail */                                                                                       \
153         [[maybe_unused]] static inline std::optional<cpptype> UnwrapImpl([[maybe_unused]] InteropCtx *ctx,   \
154                                                                          [[maybe_unused]] napi_env env,      \
155                                                                          [[maybe_unused]] napi_value jsVal); \
156     }
157 
158 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
159 #define JSCONVERT_WRAP(type) \
160     inline napi_value JSConvert##type::WrapImpl([[maybe_unused]] napi_env env, [[maybe_unused]] cpptype etsVal)
161 
162 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
163 #define JSCONVERT_UNWRAP(type)                                                  \
164     inline std::optional<JSConvert##type::cpptype> JSConvert##type::UnwrapImpl( \
165         [[maybe_unused]] InteropCtx *ctx, [[maybe_unused]] napi_env env, [[maybe_unused]] napi_value jsVal)
166 }  // namespace ark::ets::interop::js
167 
168 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_BASE_H
169