1 /* 2 * Copyright (c) 2021 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 ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H 17 #define ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H 18 19 #include <atomic> 20 #include <memory> 21 22 #include "ecmascript/js_hclass.h" 23 #include "ecmascript/mem/heap.h" 24 #include "ecmascript/mem/object_xray.h" 25 #include "ecmascript/mem/region.h" 26 #include "ecmascript/mem/space.h" 27 #include "ecmascript/mem/tagged_object.h" 28 #include "ecmascript/mem/tlab_allocator.h" 29 #include "ecmascript/taskpool/task.h" 30 31 #include "ecmascript/platform/mutex.h" 32 33 namespace panda::ecmascript { 34 class ParallelEvacuator { 35 public: ParallelEvacuator(Heap *heap)36 explicit ParallelEvacuator(Heap *heap) : heap_(heap) {} 37 ~ParallelEvacuator() = default; 38 void Initialize(); 39 void Finalize(); 40 void Evacuate(); 41 GetPromotedSize() const42 size_t GetPromotedSize() const 43 { 44 return promotedSize_; 45 } 46 GetEdenToYoungSize() const47 size_t GetEdenToYoungSize() const 48 { 49 return edenToYoungSize_; 50 } 51 private: 52 class EvacuationTask : public Task { 53 public: 54 EvacuationTask(int32_t id, uint32_t idOrder, ParallelEvacuator *evacuator); 55 ~EvacuationTask() override; 56 bool Run(uint32_t threadIndex) override; 57 58 NO_COPY_SEMANTIC(EvacuationTask); 59 NO_MOVE_SEMANTIC(EvacuationTask); 60 61 private: 62 uint32_t idOrder_; 63 ParallelEvacuator *evacuator_; 64 TlabAllocator *allocator_ {nullptr}; 65 }; 66 67 class UpdateReferenceTask : public Task { 68 public: UpdateReferenceTask(int32_t id, ParallelEvacuator *evacuator)69 UpdateReferenceTask(int32_t id, ParallelEvacuator *evacuator) : Task(id), evacuator_(evacuator) {}; 70 ~UpdateReferenceTask() override = default; 71 72 bool Run(uint32_t threadIndex) override; 73 74 NO_COPY_SEMANTIC(UpdateReferenceTask); 75 NO_MOVE_SEMANTIC(UpdateReferenceTask); 76 77 private: 78 ParallelEvacuator *evacuator_; 79 }; 80 81 class Workload { 82 public: Workload(ParallelEvacuator *evacuator, Region *region)83 Workload(ParallelEvacuator *evacuator, Region *region) : evacuator_(evacuator), region_(region) {}; 84 virtual ~Workload() = default; 85 virtual bool Process(bool isMain) = 0; GetRegion() const86 inline Region *GetRegion() const 87 { 88 return region_; 89 } 90 GetEvacuator() const91 inline ParallelEvacuator *GetEvacuator() const 92 { 93 return evacuator_; 94 } 95 protected: 96 ParallelEvacuator *evacuator_; 97 Region *region_; 98 }; 99 100 class AcquireItem { 101 public: 102 AcquireItem() = default; 103 AcquireItem(AcquireItem&& other) noexcept {(void)other;}; 104 bool TryAcquire(); 105 private: 106 std::atomic<bool> acquire_{false}; 107 }; 108 109 class WorkloadSet { 110 public: 111 inline void Add(std::unique_ptr<Workload> workload); 112 inline size_t GetWorkloadCount() const; 113 inline bool HasRemaningWorkload() const; 114 inline bool FetchSubAndCheckWorkloadCount(size_t finishedCount); 115 void PrepareWorkloads(); 116 std::optional<size_t> GetNextIndex(); 117 std::unique_ptr<ParallelEvacuator::Workload> TryGetWorkload(size_t index); 118 void Clear(); 119 private: 120 using WorkItem = std::pair<AcquireItem, std::unique_ptr<Workload>>; 121 std::vector<WorkItem> workloads_; 122 std::vector<size_t> indexList_; 123 std::atomic<size_t> indexCursor_ = 0; 124 std::atomic<size_t> remainingWorkloadNum_ = 0; 125 }; 126 127 class EvacuateWorkload : public Workload { 128 public: EvacuateWorkload(ParallelEvacuator *evacuator, Region *region)129 EvacuateWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {} 130 ~EvacuateWorkload() override = default; 131 bool Process(bool isMain) override; 132 }; 133 134 class UpdateRSetWorkload : public Workload { 135 public: UpdateRSetWorkload(ParallelEvacuator *evacuator, Region *region, bool isEdenGC)136 UpdateRSetWorkload(ParallelEvacuator *evacuator, Region *region, bool isEdenGC) 137 : Workload(evacuator, region), isEdenGC_(isEdenGC) {} 138 ~UpdateRSetWorkload() override = default; 139 bool Process(bool isMain) override; 140 private: 141 bool isEdenGC_; 142 }; 143 144 class UpdateNewToEdenRSetWorkload : public Workload { 145 public: UpdateNewToEdenRSetWorkload(ParallelEvacuator *evacuator, Region *region)146 UpdateNewToEdenRSetWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {} 147 ~UpdateNewToEdenRSetWorkload() override = default; 148 bool Process(bool isMain) override; 149 }; 150 151 class UpdateNewRegionWorkload : public Workload { 152 public: UpdateNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC)153 UpdateNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC) 154 : Workload(evacuator, region), isYoungGC_(isYoungGC) {} 155 ~UpdateNewRegionWorkload() override = default; 156 bool Process(bool isMain) override; 157 private: 158 bool isYoungGC_; 159 }; 160 161 class UpdateAndSweepNewRegionWorkload : public Workload { 162 public: UpdateAndSweepNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC)163 UpdateAndSweepNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC) 164 : Workload(evacuator, region), isYoungGC_(isYoungGC) {} 165 ~UpdateAndSweepNewRegionWorkload() override = default; 166 bool Process(bool isMain) override; 167 private: 168 bool isYoungGC_; 169 }; 170 171 template <typename WorkloadCallback> 172 void DrainWorkloads(WorkloadSet &workloadSet, WorkloadCallback callback); 173 ArrayTrackInfoSet(uint32_t threadIndex)174 std::unordered_set<JSTaggedType> &ArrayTrackInfoSet(uint32_t threadIndex) 175 { 176 return arrayTrackInfoSets_[threadIndex]; 177 } 178 179 TaggedObject* UpdateAddressAfterEvacation(TaggedObject *oldTrackInfo); 180 181 void UpdateTrackInfo(); 182 183 bool ProcessWorkloads(bool isMain = false); 184 185 void EvacuateSpace(); 186 bool EvacuateSpace(TlabAllocator *allocation, uint32_t threadIndex, uint32_t idOrder, bool isMain = false); 187 void UpdateRecordWeakReferenceInParallel(uint32_t idOrder); 188 void EvacuateRegion(TlabAllocator *allocator, Region *region, std::unordered_set<JSTaggedType> &trackSet); 189 template<bool SetEdenObject> 190 inline void SetObjectFieldRSet(TaggedObject *object, JSHClass *cls); 191 template<bool SetEdenObject> 192 inline void SetObjectRSet(ObjectSlot slot, Region *region); 193 194 inline void UpdateLocalToShareRSet(TaggedObject *object, JSHClass *cls); 195 inline void SetLocalToShareRSet(ObjectSlot slot, Region *region); 196 197 inline bool IsWholeRegionEvacuate(Region *region); 198 inline bool WholeRegionEvacuate(Region *region); 199 void VerifyValue(TaggedObject *object, ObjectSlot slot); 200 void VerifyHeapObject(TaggedObject *object); 201 202 void UpdateReference(); 203 void UpdateRoot(); 204 void UpdateWeakReference(); 205 void UpdateRecordWeakReference(); 206 template<TriggerGCType gcType> 207 void UpdateWeakReferenceOpt(); 208 template<bool IsEdenGC> 209 void UpdateRSet(Region *region); 210 void UpdateNewToEdenRSetReference(Region *region); 211 template<TriggerGCType gcType> 212 void UpdateNewRegionReference(Region *region); 213 template<TriggerGCType gcType> 214 void UpdateAndSweepNewRegionReference(Region *region); 215 template<TriggerGCType gcType> 216 void UpdateNewObjectField(TaggedObject *object, JSHClass *cls); 217 218 template<typename Callback> 219 inline bool VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback); 220 inline bool UpdateForwardedOldToNewObjectSlot(TaggedObject *object, ObjectSlot &slot, bool isWeak); 221 template<bool IsEdenGC> 222 inline bool UpdateOldToNewObjectSlot(ObjectSlot &slot); 223 inline bool UpdateNewToEdenObjectSlot(ObjectSlot &slot); 224 inline void UpdateObjectSlot(ObjectSlot &slot); 225 template<TriggerGCType gcType> 226 inline void UpdateObjectSlotOpt(ObjectSlot &slot); 227 inline void UpdateWeakObjectSlot(TaggedObject *object, ObjectSlot &slot); 228 template<TriggerGCType gcType> 229 inline bool UpdateWeakObjectSlotOpt(JSTaggedValue value, ObjectSlot &slot); 230 231 inline int CalculateEvacuationThreadNum(); 232 inline int CalculateUpdateThreadNum(); 233 void WaitFinished(); 234 235 Heap *heap_; 236 TlabAllocator *allocator_ {nullptr}; 237 238 uintptr_t waterLine_ = 0; 239 std::unordered_set<JSTaggedType> arrayTrackInfoSets_[MAX_TASKPOOL_THREAD_NUM + 1]; 240 uint32_t evacuateTaskNum_ = 0; 241 std::atomic_int parallel_ = 0; 242 Mutex mutex_; 243 ConditionVariable condition_; 244 std::atomic<size_t> promotedSize_ = 0; 245 std::atomic<size_t> edenToYoungSize_ = 0; 246 WorkloadSet evacuateWorkloadSet_; 247 WorkloadSet updateWorkloadSet_; 248 }; 249 } // namespace panda::ecmascript 250 #endif // ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H 251