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