1 /** 2 * Copyright (c) 2023-2025 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_PROXY_SHARED_REFERENCE_H_ 17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_H_ 18 19 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h" 20 #include "plugins/ets/runtime/interop_js/ets_proxy/shared_reference_flags.h" 21 22 #include <node_api.h> 23 24 #if defined(PANDA_JS_ETS_HYBRID_MODE) 25 #include "interfaces/inner_api/napi/native_node_hybrid_api.h" 26 #endif 27 28 namespace ark::ets::interop::js { 29 class InteropCtx; 30 } // namespace ark::ets::interop::js 31 32 namespace ark::ets::interop::js::ets_proxy { 33 // Forward declaration 34 class SharedReferenceStorage; 35 namespace testing { 36 class SharedReferenceStorage1GTest; 37 } // namespace testing 38 39 class SharedReference { 40 public: 41 static constexpr size_t MAX_MARK_BITS = 27U; 42 static_assert(MAX_MARK_BITS <= EtsMarkWord::INTEROP_INDEX_SIZE); 43 44 // Actual state of shared object is contained in ETS 45 void InitETSObject(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx); 46 47 // Actual state of shared object is contained in JS 48 void InitJSObject(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx); 49 50 // State of object is shared between ETS and JS 51 void InitHybridObject(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx); 52 53 using InitFn = decltype(&SharedReference::InitHybridObject); 54 GetEtsObject()55 EtsObject *GetEtsObject() const 56 { 57 ASSERT(etsRef_ != nullptr); 58 return etsRef_; 59 } 60 GetJsRef()61 napi_ref GetJsRef() const 62 { 63 return jsRef_; 64 } 65 GetCtx()66 const InteropCtx *GetCtx() const 67 { 68 ASSERT(ctx_ != nullptr); 69 return ctx_; 70 } 71 HasETSFlag()72 bool HasETSFlag() const 73 { 74 return flags_.HasBit<SharedReferenceFlags::Bit::ETS>(); 75 } 76 HasJSFlag()77 bool HasJSFlag() const 78 { 79 return flags_.HasBit<SharedReferenceFlags::Bit::JS>(); 80 } 81 82 /** 83 * Empty ref means the ref is not allocated or removed from storage and can't be used 84 * @return true if reference is empty, false - otherwise 85 */ IsEmpty()86 bool IsEmpty() const 87 { 88 return flags_.IsEmpty(); 89 } 90 91 /** 92 * Mark the reference as live. It's special method for XGC marking 93 * @return true if the method marked the reference, false if the reference has already been marked 94 */ 95 PANDA_PUBLIC_API bool MarkIfNotMarked(); 96 97 /// @return true if the refernce is marked, false - otherwise IsMarked()98 bool IsMarked() const 99 { 100 return flags_.HasBit<SharedReferenceFlags::Bit::MARK>(); 101 } 102 103 /// @class provides forward iterator for SharedReference with chain of contexts and one EtsObject 104 class Iterator { 105 public: 106 // NOLINTBEGIN(readability-identifier-naming) 107 using iterator_category = std::forward_iterator_tag; 108 using value_type = SharedReference *; 109 using difference_type = std::ptrdiff_t; 110 using pointer = value_type *; 111 using reference = value_type &; 112 // NOLINTEND(readability-identifier-naming) 113 114 friend class SharedReference; 115 116 PANDA_PUBLIC_API Iterator &operator++(); 117 PANDA_PUBLIC_API Iterator operator++(int); // NOLINT(cert-dcl21-cpp) 118 119 bool operator==(const Iterator &other) const 120 { 121 return ref_ == other.ref_; 122 } 123 124 bool operator!=(const Iterator &other) const 125 { 126 return ref_ != other.ref_; 127 } 128 129 SharedReference *operator*() 130 { 131 return const_cast<SharedReference *>(ref_); 132 } 133 134 const SharedReference *operator*() const 135 { 136 return ref_; 137 } 138 139 SharedReference *operator->() 140 { 141 return const_cast<SharedReference *>(ref_); 142 } 143 144 const SharedReference *operator->() const 145 { 146 return ref_; 147 } 148 149 Iterator() = default; Iterator(const SharedReference * ref)150 explicit Iterator(const SharedReference *ref) : ref_(ref) {} 151 DEFAULT_COPY_SEMANTIC(Iterator); 152 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(Iterator); 153 ~Iterator() = default; 154 155 private: 156 const SharedReference *ref_ {nullptr}; 157 }; 158 GetIterator()159 Iterator GetIterator() const 160 { 161 return Iterator(this); 162 } 163 164 friend std::ostream &operator<<(std::ostream &out, const SharedReference *ref) 165 { 166 out << static_cast<const void *>(ref); 167 if (LIKELY(ref != nullptr)) { 168 out << ": | ETSObject:" << ref->etsRef_ << " | napi_ref:" << ref->jsRef_ << " | ctx:" << ref->ctx_ << " | " 169 << ref->flags_ << " |"; 170 } 171 return out; 172 } 173 174 private: 175 friend class SharedReferenceSanity; 176 friend class SharedReferenceStorage; 177 friend class testing::SharedReferenceStorage1GTest; 178 179 void InitRef(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx); 180 SetETSObject(EtsObject * obj)181 void SetETSObject(EtsObject *obj) 182 { 183 ASSERT(obj != nullptr); 184 etsRef_ = obj; 185 } 186 HasReference(EtsObject * etsObject)187 static bool HasReference(EtsObject *etsObject) 188 { 189 return etsObject->HasInteropIndex(); 190 } 191 ExtractMaybeIndex(EtsObject * etsObject)192 static uint32_t ExtractMaybeIndex(EtsObject *etsObject) 193 { 194 ASSERT(HasReference(etsObject)); 195 return etsObject->GetInteropIndex(); 196 } 197 198 /// Unset mark flag from the reference Unmark()199 void Unmark() 200 { 201 flags_.Unmark(); 202 } 203 204 /* Possible values: 205 * ets_proxy: {instance, proxy} 206 * extensible ets_proxy: {proxy-base, extender-proxy} 207 * js_proxy: {proxy, instance} 208 * extensible js_proxy: {extender-proxy, proxy-base} 209 */ 210 EtsObject *etsRef_ {}; 211 napi_ref jsRef_ {}; 212 const InteropCtx *ctx_ {}; 213 214 SharedReferenceFlags flags_ {}; 215 }; 216 217 } // namespace ark::ets::interop::js::ets_proxy 218 219 #endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_H_ 220