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