1 /** 2 * Copyright (c) 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_PLUGINGS_ETS_RUNTIME_INTEROP_JS_HYBRID_XGC_XGC_H 17 #define PANDA_PLUGINGS_ETS_RUNTIME_INTEROP_JS_HYBRID_XGC_XGC_H 18 19 #include "hybrid/ecma_vm_interface.h" 20 #include "plugins/ets/runtime/interop_js/app_state_manager.h" 21 #include "plugins/ets/runtime/interop_js/sts_vm_interface_impl.h" 22 #include "runtime/mem/gc/gc_trigger.h" 23 24 namespace ark::ets { 25 class PandaEtsVM; 26 } // namespace ark::ets 27 28 namespace ark::ets::interop::js { 29 30 class InteropCtx; 31 namespace ets_proxy { 32 class SharedReferenceStorage; 33 class SharedReferenceStorageVerifier; 34 enum class XgcStatus; 35 } // namespace ets_proxy 36 37 /** 38 * Cross-reference garbage collector. 39 * Implements logic to collect cross-references between JS and ETS in SharedReferenceStorage. 40 */ 41 class XGC final : public mem::GCTrigger { 42 public: 43 NO_COPY_SEMANTIC(XGC); 44 NO_MOVE_SEMANTIC(XGC); 45 ~XGC() override = default; 46 47 /// @enum represents XGC trigger policy types 48 enum class TriggerPolicy : uint8_t { 49 INVALID, // Invalid trigger, it should not be used 50 DEFAULT, // Default trigger 51 FORCE, // Run on each allocation 52 NEVER, // Never trigger XGC (disable) 53 }; 54 55 /** 56 * Create instance of XGC if it was not created before. Runtime should be existed before the XGC creation 57 * @param mainCoro main coroutine 58 * @return true if the instance successfully created, false - otherwise 59 */ 60 [[nodiscard]] PANDA_PUBLIC_API static bool Create(PandaEtsVM *vm, ets_proxy::SharedReferenceStorage *storage, 61 STSVMInterfaceImpl *stsVmIface); 62 63 /// @return current instance of XGC 64 static XGC *GetInstance(); 65 66 /** 67 * Destroy the current instance of XGC if the instance is existed. Runtime should be existed before the XGC 68 * destruction 69 * @return true if the instance successfully destroyed, false - otherwise 70 */ 71 PANDA_PUBLIC_API static bool Destroy(); 72 73 /** 74 * Check trigger condition and post XGC task to gc queue and 75 * trigger XMark for all related JS virtual machines if needed 76 * @param gc GC using in the current VM 77 */ 78 void TriggerGcIfNeeded(mem::GC *gc) override; 79 80 /** 81 * Notify XGC about the new interop context attached to STS VM 82 * @param context attached interop context 83 * @remark the passed interop context must not be registered (attached) in XGC 84 */ 85 void OnAttach(const InteropCtx *context); 86 87 /** 88 * Notify XGC about the interop context detached from STS VM 89 * @param context detached interop context 90 * @remark the passed interop context must be registered (attached) in XGC 91 * @see OnAttach 92 */ 93 void OnDetach(const InteropCtx *context); 94 95 /** 96 * Post XGC task to gc queue and trigger XMark for all related JS virtual machines 97 * @param gc GC using in the current VM 98 * @return true if XGC successfully triggered, false - otherwise 99 */ 100 bool Trigger(mem::GC *gc, PandaUniquePtr<GCTask> task); 101 102 /// @return XGC trigger type value GetType()103 mem::GCTriggerType GetType() const override 104 { 105 return mem::GCTriggerType::XGC; 106 } 107 108 /// GCListener specific public methods /// 109 110 void GCStarted(const GCTask &task, size_t heapSize) override; 111 void GCFinished(const GCTask &task, size_t heapSizeBeforeGc, size_t heapSize) override; 112 void GCPhaseStarted(mem::GCPhase phase) override; 113 void GCPhaseFinished(mem::GCPhase phase) override; 114 115 private: 116 // For allocation of XGC with the private constructor by internal allocator 117 friend mem::Allocator; 118 friend void STSVMInterfaceImpl::MarkFromObject([[maybe_unused]] void *obj); 119 120 XGC(PandaEtsVM *vm, STSVMInterfaceImpl *stsVmIface, ets_proxy::SharedReferenceStorage *storage); 121 static XGC *instance_; 122 123 /// @return true if need to trigger XGC by policy and special conditions, false - otherwise 124 bool NeedToTriggerXGC(const mem::GC *gc) const; 125 126 /// @return new target threshold storage size for XGC trigger 127 size_t ComputeNewSize(); 128 129 /// Unmark all cross references before initial mark 130 void UnmarkAll(); 131 132 /** 133 * Start marking from specific cross reference object 134 * @param data native data from a JS VM with cross reference data 135 */ 136 void MarkFromObject(void *data); 137 138 /// Remark cross references allocated during concurrent mark phase 139 void Remark(); 140 141 /// Sweep unmarked cross references on STW 142 void Sweep(); 143 144 /// Finish XGC process (on the end of Remark phase or the end of GC) 145 void Finish(); 146 147 /** 148 * Notify all related waiters that the XGC process has been finished 149 * @see WaitForFinishXGC 150 * @see Finish 151 */ 152 void NotifyToFinishXGC(); 153 154 /** 155 * Wait until XGC process completed 156 * @see NotifyToFinishXGC 157 * @see OnDetach 158 */ 159 void WaitForFinishXGC(); 160 161 void VerifySharedReferences(ets_proxy::XgcStatus status); 162 163 /// External specific fields /// 164 165 PandaEtsVM *vm_ {nullptr}; 166 ets_proxy::SharedReferenceStorage *storage_ {nullptr}; 167 STSVMInterfaceImpl *stsVmIface_ {nullptr}; 168 169 /// XGC current state specific fields /// 170 171 os::memory::Mutex finishXgcLock_; 172 os::memory::ConditionVariable finishXgcCV_ GUARDED_BY(finishXgcLock_); 173 std::atomic_bool isXGcInProgress_ {false}; 174 bool remarkFinished_ {false}; // GUARDED_BY(mutatorLock) 175 176 /// Trigger specific fields /// 177 178 size_t beforeGCStorageSize_ {0U}; 179 const size_t minimalThresholdSize_ {0U}; 180 const size_t increaseThresholdPercent_ {0U}; 181 // We can load a value of the variable from several threads, so need to use atomic 182 std::atomic<size_t> targetThreasholdSize_ {0U}; 183 const TriggerPolicy treiggerPolicy_ {TriggerPolicy::INVALID}; 184 const bool enableXgcVerifier_ {false}; 185 }; 186 187 } // namespace ark::ets::interop::js 188 189 #endif // PANDA_PLUGINGS_ETS_RUNTIME_INTEROP_JS_HYBRID_XGC_XGC_H 190