• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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_ETS_CLASS_WRAPPER_H_
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_CLASS_WRAPPER_H_
18 
19 #include "libpandabase/macros.h"
20 #include "plugins/ets/runtime/ets_utils.h"
21 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_field_wrapper.h"
22 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_method_wrapper.h"
23 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_object_reference.h"
24 #include "plugins/ets/runtime/interop_js/js_proxy/js_proxy.h"
25 #include "plugins/ets/runtime/interop_js/js_refconvert.h"
26 #include "plugins/ets/runtime/interop_js/interop_common.h"
27 
28 #include <node_api.h>
29 #include <vector>
30 
31 namespace ark::ets {
32 class EtsClass;
33 }  // namespace ark::ets
34 
35 namespace ark::ets::interop::js::ets_proxy {
36 
37 using EtsClassWrappersCache = WrappersCache<EtsClass *, EtsClassWrapper>;
38 
39 class EtsClassWrapper {
40 public:
41     // clang-format off
42     static constexpr auto FIELD_ATTR         = static_cast<napi_property_attributes>(napi_writable | napi_enumerable);
43     static constexpr auto METHOD_ATTR        = napi_default;
44     // NOLINTBEGIN(hicpp-signed-bitwise)
45     static constexpr auto STATIC_FIELD_ATTR  = static_cast<napi_property_attributes>(napi_writable | napi_enumerable |\
46                                                                        napi_static);
47     // NOLINTEND(hicpp-signed-bitwise)
48     static constexpr auto STATIC_METHOD_ATTR = napi_static;
49     // clang-format on
50 
51     using OverloadsMap = std::unordered_map<uint8_t const *, char const *, utf::Mutf8Hash, utf::Mutf8Equal>;
52 
53     static std::unique_ptr<EtsClassWrapper> Create(InteropCtx *ctx, EtsClass *etsClass,
54                                                    const char *jsBuiltinName = nullptr,
55                                                    const OverloadsMap *overloads = nullptr);
56 
57     static EtsClassWrapper *Get(InteropCtx *ctx, EtsClass *etsClass);
58 
59     static std::unique_ptr<JSRefConvert> CreateJSRefConvertEtsProxy(InteropCtx *ctx, Class *klass);
60     static std::unique_ptr<JSRefConvert> CreateJSRefConvertJSProxy(InteropCtx *ctx, Class *klass);
61 
IsEtsGlobalClass()62     bool IsEtsGlobalClass() const
63     {
64         return IsEtsGlobalClassName(etsClass_->GetDescriptor());
65     }
66 
GetEtsClass()67     EtsClass *GetEtsClass()
68     {
69         return etsClass_;
70     }
71 
72     EtsMethodSet *GetMethod(const std::string &name) const;
73 
GetJsCtor(napi_env env)74     napi_value GetJsCtor(napi_env env) const
75     {
76         return GetReferenceValue(env, jsCtorRef_);
77     }
78 
HasBuiltin()79     bool HasBuiltin() const
80     {
81         return jsBuiltinCtorRef_ != nullptr;
82     }
83 
GetBuiltin(napi_env env)84     napi_value GetBuiltin(napi_env env) const
85     {
86         ASSERT(HasBuiltin());
87         return GetReferenceValue(env, jsBuiltinCtorRef_);
88     }
89 
SetJSBuiltinMatcher(std::function<EtsObject * (InteropCtx *,napi_value,bool)> && matcher)90     void SetJSBuiltinMatcher(std::function<EtsObject *(InteropCtx *, napi_value, bool)> &&matcher)
91     {
92         jsBuiltinMatcher_ = std::move(matcher);
93     }
94 
95     napi_value Wrap(InteropCtx *ctx, EtsObject *etsObject);
96     EtsObject *Unwrap(InteropCtx *ctx, napi_value jsValue);
97 
98     EtsObject *UnwrapEtsProxy(InteropCtx *ctx, napi_value jsValue);
99     EtsObject *CreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsValue);
100 
101     ~EtsClassWrapper() = default;
102 
103 private:
EtsClassWrapper(EtsClass * etsCls)104     explicit EtsClassWrapper(EtsClass *etsCls) : etsClass_(etsCls) {}
105     NO_COPY_SEMANTIC(EtsClassWrapper);
106     NO_MOVE_SEMANTIC(EtsClassWrapper);
107 
108     bool SetupHierarchy(InteropCtx *ctx, const char *jsBuiltinName);
109 
110     using PropsMap =
111         std::unordered_map<uint8_t const *, std::variant<EtsMethodSet *, Field *>, utf::Mutf8Hash, utf::Mutf8Equal>;
112     using FieldsVec = std::vector<Field *>;
113     using MethodsVec = std::vector<EtsMethodSet *>;
114 
115     std::pair<FieldsVec, MethodsVec> CalculateProperties(const OverloadsMap *overloads);
116     void UpdatePropsWithBaseClasses(PropsMap *props);
117     void CollectConstructors(PropsMap *props);
118     void CollectClassMethods(PropsMap *props, const OverloadsMap *overloads);
119     std::pair<FieldsVec, MethodsVec> CalculateFieldsAndMethods(const PropsMap &props);
120     std::vector<napi_property_descriptor> BuildJSProperties(Span<Field *> fields, Span<EtsMethodSet *> methods);
121     EtsClassWrapper *LookupBaseWrapper(EtsClass *klass);
122 
123     static napi_value JSCtorCallback(napi_env env, napi_callback_info cinfo);
124     bool CreateAndWrap(napi_env env, napi_value jsNewtarget, napi_value jsThis, Span<napi_value> jsArgs);
125 
126     static void ThrowJSErrorNotAssignable(napi_env env, EtsClass *fromKlass, EtsClass *toKlass);
127 
GetFields()128     Span<EtsFieldWrapper> GetFields()
129     {
130         return Span<EtsFieldWrapper>(etsFieldWrappers_.get(), numFields_);
131     }
132 
GetMethods()133     Span<LazyEtsMethodWrapperLink> GetMethods()
134     {
135         return Span<LazyEtsMethodWrapperLink>(etsMethodWrappers_.get(), numMethods_);
136     }
137 
138     EtsClass *const etsClass_ {};
139     EtsClassWrapper *baseWrapper_ {};
140 
141     LazyEtsMethodWrapperLink etsCtorLink_ {};
142     napi_ref jsCtorRef_ {};
143 
144     // For built-in classes
145     napi_ref jsBuiltinCtorRef_ {};
146     std::function<EtsObject *(InteropCtx *, napi_value, bool)> jsBuiltinMatcher_;
147 
148     std::unique_ptr<js_proxy::JSProxy> jsproxyWrapper_ {};
149 
150     // NOTE(vpukhov): allocate inplace to reduce memory consumption
151     std::unique_ptr<LazyEtsMethodWrapperLink[]> etsMethodWrappers_;  // NOLINT(modernize-avoid-c-arrays)
152     std::unique_ptr<EtsFieldWrapper[]> etsFieldWrappers_;            // NOLINT(modernize-avoid-c-arrays)
153     std::vector<std::unique_ptr<EtsMethodSet>> etsMethods_;
154     uint32_t numMethods_ {};
155     uint32_t numFields_ {};
156 };
157 
158 }  // namespace ark::ets::interop::js::ets_proxy
159 
160 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_CLASS_WRAPPER_H_
161