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