• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
3  * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_CLASS_WRAPPER_H_
18 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_CLASS_WRAPPER_H_
19 
20 #include "libpandabase/macros.h"
21 #include "plugins/ets/runtime/ets_utils.h"
22 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_field_wrapper.h"
23 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_method_wrapper.h"
24 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_object_reference.h"
25 #include "plugins/ets/runtime/interop_js/js_proxy/js_proxy.h"
26 #include "plugins/ets/runtime/interop_js/js_refconvert.h"
27 #include "plugins/ets/runtime/interop_js/interop_common.h"
28 
29 #include <node_api.h>
30 #include <vector>
31 
32 namespace ark::ets {
33 class EtsClass;
34 }  // namespace ark::ets
35 
36 namespace ark::ets::interop::js::ets_proxy {
37 
38 using EtsClassWrappersCache = WrappersCache<EtsClass *, EtsClassWrapper>;
39 
40 class EtsClassWrapper {
41 public:
42     // clang-format off
43     static constexpr auto FIELD_ATTR         = static_cast<napi_property_attributes>(napi_writable | napi_enumerable);
44     static constexpr auto METHOD_ATTR        = napi_default;
45     // NOLINTBEGIN(hicpp-signed-bitwise)
46     static constexpr auto STATIC_FIELD_ATTR  = static_cast<napi_property_attributes>(napi_writable | napi_enumerable |\
47                                                                        napi_static);
48     // NOLINTEND(hicpp-signed-bitwise)
49     static constexpr auto STATIC_METHOD_ATTR = napi_static;
50     // clang-format on
51 
52     using OverloadsMap =
53         std::unordered_multimap<uint8_t const *, std::pair<char const *, uint32_t>, utf::Mutf8Hash, utf::Mutf8Equal>;
54 
55     static std::unique_ptr<EtsClassWrapper> Create(InteropCtx *ctx, EtsClass *etsClass,
56                                                    const char *jsBuiltinName = nullptr,
57                                                    const OverloadsMap *overloads = nullptr);
58 
59     static EtsClassWrapper *Get(InteropCtx *ctx, EtsClass *etsClass);
60 
61     static std::unique_ptr<JSRefConvert> CreateJSRefConvertEtsProxy(InteropCtx *ctx, Class *klass);
62     static std::unique_ptr<JSRefConvert> CreateJSRefConvertJSProxy(InteropCtx *ctx, Class *klass);
63     static std::unique_ptr<JSRefConvert> CreateJSRefConvertEtsInterface(InteropCtx *ctx, Class *klass);
64 
IsEtsGlobalClass()65     bool IsEtsGlobalClass() const
66     {
67         return IsEtsGlobalClassName(etsClass_->GetDescriptor());
68     }
69 
GetEtsClass()70     EtsClass *GetEtsClass()
71     {
72         return etsClass_;
73     }
74 
75     EtsMethodSet *GetMethod(const std::string &name) const;
76 
GetJsCtor(napi_env env)77     napi_value GetJsCtor(napi_env env) const
78     {
79         return GetReferenceValue(env, jsCtorRef_);
80     }
81 
HasBuiltin()82     bool HasBuiltin() const
83     {
84         return jsBuiltinCtorRef_ != nullptr;
85     }
86 
GetBuiltin(napi_env env)87     napi_value GetBuiltin(napi_env env) const
88     {
89         ASSERT(HasBuiltin());
90         return GetReferenceValue(env, jsBuiltinCtorRef_);
91     }
92 
SetJSBuiltinMatcher(std::function<EtsObject * (InteropCtx *,napi_value,bool)> && matcher)93     void SetJSBuiltinMatcher(std::function<EtsObject *(InteropCtx *, napi_value, bool)> &&matcher)
94     {
95         jsBuiltinMatcher_ = std::move(matcher);
96     }
97 
98     napi_value Wrap(InteropCtx *ctx, EtsObject *etsObject);
99     EtsObject *Unwrap(InteropCtx *ctx, napi_value jsValue);
100 
101     EtsObject *UnwrapEtsProxy(InteropCtx *ctx, napi_value jsValue);
102     EtsObject *CreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsValue);
103 
104     ~EtsClassWrapper() = default;
105 
106 private:
EtsClassWrapper(EtsClass * etsCls)107     explicit EtsClassWrapper(EtsClass *etsCls) : etsClass_(etsCls) {}
108     NO_COPY_SEMANTIC(EtsClassWrapper);
109     NO_MOVE_SEMANTIC(EtsClassWrapper);
110 
111     bool SetupHierarchy(InteropCtx *ctx, const char *jsBuiltinName);
112 
113     using PropsMap =
114         std::unordered_map<uint8_t const *, std::variant<EtsMethodSet *, Field *>, utf::Mutf8Hash, utf::Mutf8Equal>;
115     using GetterSetterPropsMap = std::unordered_map<std::string, napi_property_descriptor>;
116     using FieldsVec = std::vector<Field *>;
117     using MethodsVec = std::vector<EtsMethodSet *>;
118 
119     std::pair<FieldsVec, MethodsVec> CalculateProperties(const OverloadsMap *overloads);
120     void SetBaseWrapperMethods(napi_env env, const EtsClassWrapper::MethodsVec &methods);
121     void UpdatePropsWithBaseClasses(PropsMap *props);
122     void CollectConstructors(PropsMap *props);
123     void CollectClassMethods(PropsMap *props, const OverloadsMap *overloads);
124     bool HasOverloadsMethod(const OverloadsMap *overloads, Method *m);
125     std::pair<FieldsVec, MethodsVec> CalculateFieldsAndMethods(const PropsMap &props);
126     std::vector<napi_property_descriptor> BuildJSProperties(napi_env &env, Span<Field *> fields,
127                                                             Span<EtsMethodSet *> methods);
128 
129     static napi_value GetGlobalSymbolIterator(napi_env &env);
130 
131     EtsClassWrapper *LookupBaseWrapper(EtsClass *klass);
132     void BuildGetterSetterFieldProperties(GetterSetterPropsMap &propMap, EtsMethodSet *method);
133     void SetUpMimicHandler(napi_env env);
134     static napi_value CreateProxy(napi_env env, napi_value jsCtor, EtsClassWrapper *thisWrapper);
135     static napi_value MimicGetHandler(napi_env env, napi_callback_info info);
136     static napi_value MimicSetHandler(napi_env env, napi_callback_info info);
137 
138     static napi_value JSCtorCallback(napi_env env, napi_callback_info cinfo);
139     bool CreateAndWrap(napi_env env, napi_value jsNewtarget, napi_value jsThis, Span<napi_value> jsArgs);
140 
141     static void ThrowJSErrorNotAssignable(napi_env env, EtsClass *fromKlass, EtsClass *toKlass);
142 
GetFields()143     Span<EtsFieldWrapper> GetFields()
144     {
145         return Span<EtsFieldWrapper>(etsFieldWrappers_.get(), numFields_);
146     }
147 
GetMethods()148     Span<LazyEtsMethodWrapperLink> GetMethods()
149     {
150         return Span<LazyEtsMethodWrapperLink>(etsMethodWrappers_.get(), numMethods_);
151     }
152 
153     EtsClass *const etsClass_ {};
154     EtsClassWrapper *baseWrapper_ {};
155 
156     LazyEtsMethodWrapperLink etsCtorLink_ {};
157     napi_ref jsCtorRef_ {};
158 
159     // For built-in classes
160     napi_ref jsBuiltinCtorRef_ {};
161     std::function<EtsObject *(InteropCtx *, napi_value, bool)> jsBuiltinMatcher_;
162 
163     js_proxy::JSProxy *jsproxyWrapper_ {};
164 
165     // NOTE(vpukhov): allocate inplace to reduce memory consumption
166     std::unique_ptr<LazyEtsMethodWrapperLink[]> etsMethodWrappers_;  // NOLINT(modernize-avoid-c-arrays)
167     std::unique_ptr<EtsFieldWrapper[]> etsFieldWrappers_;            // NOLINT(modernize-avoid-c-arrays)
168     std::vector<std::unique_ptr<EtsMethodSet>> etsMethods_;
169     std::vector<std::unique_ptr<EtsFieldWrapper>> getterSetterFieldWrappers_;
170     uint32_t numMethods_ {};
171     uint32_t numFields_ {};
172 
173     bool needProxy_ = false;
174     napi_ref jsProxyCtorRef_ {};
175     napi_ref jsProxyHandlerRef_ {};
176 
177     static constexpr const char *INTERFACE_ITERABLE_NAME = "escompat.IterableIterator";
178 };
179 
180 }  // namespace ark::ets::interop::js::ets_proxy
181 
182 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_CLASS_WRAPPER_H_
183