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_STORAGE_H_ 17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_STORAGE_H_ 18 19 #include "libpandabase/macros.h" 20 #include "plugins/ets/runtime/ets_vm.h" 21 #include "plugins/ets/runtime/interop_js/ets_proxy/shared_reference.h" 22 #include "plugins/ets/runtime/interop_js/ets_proxy/mem/items_pool.h" 23 #include "plugins/ets/runtime/mem/root_provider.h" 24 #include "plugins/ets/runtime/types/ets_object.h" 25 26 namespace ark::ets::interop::js { 27 // Forward declarations 28 class InteropCtx; 29 } // namespace ark::ets::interop::js 30 31 namespace ark::ets::interop::js::ets_proxy { 32 class SharedReferenceStorageVerifier; 33 namespace testing { 34 class SharedReferenceStorage1GTest; 35 } // namespace testing 36 37 using SharedReferencePool = ItemsPool<SharedReference, SharedReference::MAX_MARK_BITS>; 38 39 // NOLINTNEXTLINE(fuchsia-multiple-inheritance) 40 class SharedReferenceStorage : private SharedReferencePool, public mem::RootProvider { 41 public: 42 PANDA_PUBLIC_API static PandaUniquePtr<SharedReferenceStorage> Create(PandaEtsVM *vm); 43 ~SharedReferenceStorage() override; 44 45 using PreInitJSObjectCallback = std::function<napi_value(SharedReference **)>; 46 47 /// @return current storage size Size()48 size_t Size() const 49 { 50 return SharedReferencePool::Size(); 51 } 52 53 /// @return maximum possible storage size MaxSize()54 size_t MaxSize() const 55 { 56 return SharedReferencePool::MaxSize(); 57 } 58 59 PANDA_PUBLIC_API SharedReference *CreateETSObjectRef(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject, 60 const PreInitJSObjectCallback &preInitCallback = nullptr); 61 SharedReference *CreateJSObjectRef(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject); 62 63 SharedReference *CreateJSObjectRefwithWrap(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject); 64 65 SharedReference *CreateHybridObjectRef(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject); 66 67 PANDA_PUBLIC_API SharedReference *GetReference(napi_env env, napi_value jsObject) const; 68 PANDA_PUBLIC_API SharedReference *GetReference(EtsObject *etsObject) const; 69 70 napi_value GetJsObject(EtsObject *etsObject, napi_env env) const; 71 bool HasReference(EtsObject *etsObject, napi_env env); 72 73 void NotifyXGCStarted(); 74 void NotifyXGCFinished(); 75 76 /** 77 * @brief Visit all non-empty refs and call visitor as vm root for EtsObject from the ref 78 * @param visitor gc root visitor 79 */ 80 void VisitRoots(const GCRootVisitor &visitor) override; 81 82 /// Update ref in the storage for EtsObject-s after moving phase 83 void UpdateRefs(const GCRootUpdater &gcRootUpdater) override; 84 85 /// Remove all unmarked refs after XGC (can be run concurrently) 86 void SweepUnmarkedRefs(); 87 88 /** 89 * Delete all shared references with specific context from the storage 90 * @param ctx interop context 91 * @remark interop context calls the method on destruction 92 */ 93 void DeleteAllReferencesWithCtx(const InteropCtx *ctx); 94 95 /// Clear mark bit for all shared references 96 PANDA_PUBLIC_API void UnmarkAll(); 97 98 /** 99 * Extract one SharedRefrence from set of references allocated during XGC concurrent marking pahse 100 * @return valid SharedReference or nullptr if no more references in the set 101 */ ExtractRefAllocatedDuringXGC()102 SharedReference *ExtractRefAllocatedDuringXGC() 103 { 104 os::memory::WriteLockHolder lock(storageLock_); 105 if (refsAllocatedDuringXGC_.empty()) { 106 return nullptr; 107 } 108 return refsAllocatedDuringXGC_.extract(refsAllocatedDuringXGC_.begin()).value(); 109 } 110 111 static constexpr size_t MAX_POOL_SIZE = (sizeof(void *) > 4) ? 1_GB : 64_MB; 112 static constexpr std::string_view PROXY_NAPI_WRAPPER = "_proxynapiwrapper"; 113 114 private: SharedReferenceStorage(PandaEtsVM * vm,void * data,size_t size)115 SharedReferenceStorage(PandaEtsVM *vm, void *data, size_t size) : SharedReferencePool(data, size), vm_(vm) {} 116 NO_COPY_SEMANTIC(SharedReferenceStorage); 117 NO_MOVE_SEMANTIC(SharedReferenceStorage); 118 119 template <SharedReference::InitFn REF_INIT> 120 SharedReference *CreateRefCommon(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject, 121 const PreInitJSObjectCallback &callback = nullptr); 122 GetCurrent()123 PANDA_PUBLIC_API static SharedReferenceStorage *GetCurrent() 124 { 125 ASSERT(sharedStorage_ != nullptr); 126 return sharedStorage_; 127 } 128 129 template <SharedReference::InitFn REF_INIT> 130 PANDA_PUBLIC_API inline SharedReference *CreateReference(InteropCtx *ctx, EtsHandle<EtsObject> etsObject, 131 napi_ref jsRef) REQUIRES(storageLock_); 132 PANDA_PUBLIC_API SharedReference *GetReference(void *data) const; 133 PANDA_PUBLIC_API void RemoveReference(SharedReference *sharedRef); 134 /** 135 * Remove all unmarked references from related chain which contains passed shared references 136 * @param sharedRef non-empty shared reference from this storage table 137 * @note the method should be called under the storage write-lock 138 */ 139 void DeleteUnmarkedReferences(SharedReference *sharedRef) REQUIRES(storageLock_); 140 141 /** 142 * Delete napi_ref for passed shared reference and remove the shared reference from the table 143 * @param sharedRef non-empty shared reference from this storage table 144 * @note the method should be called under the storage write-lock 145 */ 146 void DeleteJSRefAndRemoveReference(SharedReference *sharedRef) REQUIRES(storageLock_); 147 148 /** 149 * Delete one reference by predicate from references chain related with passed reference 150 * @param sharedRef non-empty shared reference from processing references chain 151 * @param deletePredicate predicate with condition for a reference deleting 152 * @return true if chain contains reference for removing by predicate and the reference was deleted from the chain, 153 * false - otherwise 154 */ 155 bool DeleteReference(SharedReference *sharedRef, 156 const std::function<bool(const SharedReference *sharedRef)> &deletePredicate) 157 REQUIRES(storageLock_); 158 159 /// Helper method for DeleteReference 160 void DeleteReferenceFromChain(EtsObject *etsObject, SharedReference *prevRef, SharedReference *removingRef, 161 uint32_t nextIndex) REQUIRES(storageLock_); 162 163 bool HasReferenceWithCtx(SharedReference *ref, InteropCtx *ctx) const; 164 165 PANDA_PUBLIC_API bool CheckAlive(void *data); 166 friend class SharedReference; 167 friend class SharedReference::Iterator; 168 friend class testing::SharedReferenceStorage1GTest; 169 // Allocator calls our protected ctor 170 friend class mem::Allocator; 171 friend class SharedReferenceStorageVerifier; 172 173 PANDA_PUBLIC_API static SharedReferenceStorage *sharedStorage_; 174 175 PandaEtsVM *vm_ {nullptr}; 176 mutable os::memory::RWLock storageLock_; GUARDED_BY(storageLock_)177 bool isXGCinProgress_ GUARDED_BY(storageLock_) {false}; // CC-OFF(G.FMT.03) project code style 178 PandaUnorderedSet<SharedReference *> refsAllocatedDuringXGC_ GUARDED_BY(storageLock_); 179 }; 180 181 } // namespace ark::ets::interop::js::ets_proxy 182 183 #endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_STORAGE_H_ 184