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 "libpandabase/os/mutex.h" 32 33 namespace panda::ecmascript { 34 class ParallelEvacuator { 35 public: ParallelEvacuator(Heap * heap)36 explicit ParallelEvacuator(Heap *heap) : heap_(heap), objXRay_(heap->GetEcmaVM()) {} 37 ~ParallelEvacuator() = default; 38 void Initialize(); 39 void Finalize(); 40 void Evacuate(); 41 GetPromotedSize()42 size_t GetPromotedSize() const 43 { 44 return promotedSize_; 45 } 46 47 private: 48 class EvacuationTask : public Task { 49 public: 50 EvacuationTask(int32_t id, ParallelEvacuator *evacuator); 51 ~EvacuationTask() override; 52 bool Run(uint32_t threadIndex) override; 53 54 NO_COPY_SEMANTIC(EvacuationTask); 55 NO_MOVE_SEMANTIC(EvacuationTask); 56 57 private: 58 ParallelEvacuator *evacuator_; 59 TlabAllocator *allocator_ {nullptr}; 60 }; 61 62 class UpdateReferenceTask : public Task { 63 public: UpdateReferenceTask(int32_t id,ParallelEvacuator * evacuator)64 UpdateReferenceTask(int32_t id, ParallelEvacuator *evacuator) : Task(id), evacuator_(evacuator) {}; 65 ~UpdateReferenceTask() override = default; 66 67 bool Run(uint32_t threadIndex) override; 68 69 NO_COPY_SEMANTIC(UpdateReferenceTask); 70 NO_MOVE_SEMANTIC(UpdateReferenceTask); 71 72 private: 73 ParallelEvacuator *evacuator_; 74 }; 75 76 class Workload { 77 public: Workload(ParallelEvacuator * evacuator,Region * region)78 Workload(ParallelEvacuator *evacuator, Region *region) : evacuator_(evacuator), region_(region) {}; 79 virtual ~Workload() = default; 80 virtual bool Process(bool isMain) = 0; GetRegion()81 inline Region *GetRegion() const 82 { 83 return region_; 84 } 85 GetEvacuator()86 inline ParallelEvacuator *GetEvacuator() const 87 { 88 return evacuator_; 89 } 90 protected: 91 ParallelEvacuator *evacuator_; 92 Region *region_; 93 }; 94 95 class EvacuateWorkload : public Workload { 96 public: EvacuateWorkload(ParallelEvacuator * evacuator,Region * region)97 EvacuateWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {} 98 ~EvacuateWorkload() override = default; 99 bool Process(bool isMain) override; 100 }; 101 102 class UpdateRSetWorkload : public Workload { 103 public: UpdateRSetWorkload(ParallelEvacuator * evacuator,Region * region)104 UpdateRSetWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {} 105 ~UpdateRSetWorkload() override = default; 106 bool Process(bool isMain) override; 107 }; 108 109 class UpdateNewRegionWorkload : public Workload { 110 public: UpdateNewRegionWorkload(ParallelEvacuator * evacuator,Region * region)111 UpdateNewRegionWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {} 112 ~UpdateNewRegionWorkload() override = default; 113 bool Process(bool isMain) override; 114 }; 115 116 class UpdateAndSweepNewRegionWorkload : public Workload { 117 public: UpdateAndSweepNewRegionWorkload(ParallelEvacuator * evacuator,Region * region)118 UpdateAndSweepNewRegionWorkload(ParallelEvacuator *evacuator, Region *region) 119 : Workload(evacuator, region) {} 120 ~UpdateAndSweepNewRegionWorkload() override = default; 121 bool Process(bool isMain) override; 122 }; 123 124 bool ProcessWorkloads(bool isMain = false); 125 126 void EvacuateSpace(); 127 bool EvacuateSpace(TlabAllocator *allocation, bool isMain = false); 128 void EvacuateRegion(TlabAllocator *allocator, Region *region); 129 inline void SetObjectFieldRSet(TaggedObject *object, JSHClass *cls); 130 inline void SetObjectRSet(ObjectSlot slot, Region *region); 131 132 inline bool IsWholeRegionEvacuate(Region *region); 133 void VerifyValue(TaggedObject *object, ObjectSlot slot); 134 void VerifyHeapObject(TaggedObject *object); 135 136 void UpdateReference(); 137 void UpdateRoot(); 138 void UpdateWeakReference(); 139 void UpdateRecordWeakReference(); 140 void UpdateRSet(Region *region); 141 void UpdateNewRegionReference(Region *region); 142 void UpdateAndSweepNewRegionReference(Region *region); 143 void UpdateNewObjectField(TaggedObject *object, JSHClass *cls); 144 145 template<typename Callback> 146 inline bool VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback); 147 inline bool UpdateOldToNewObjectSlot(ObjectSlot &slot); 148 inline void UpdateObjectSlot(ObjectSlot &slot); 149 inline void UpdateWeakObjectSlot(TaggedObject *object, ObjectSlot &slot); 150 151 inline std::unique_ptr<Workload> GetWorkloadSafe(); 152 inline void AddWorkload(std::unique_ptr<Workload> region); 153 154 inline int CalculateEvacuationThreadNum(); 155 inline int CalculateUpdateThreadNum(); 156 void WaitFinished(); 157 158 Heap *heap_; 159 TlabAllocator *allocator_ {nullptr}; 160 ObjectXRay objXRay_; 161 162 uintptr_t waterLine_ = 0; 163 std::vector<std::unique_ptr<Workload>> workloads_; 164 std::atomic_int parallel_ = 0; 165 os::memory::Mutex mutex_; 166 os::memory::ConditionVariable condition_; 167 std::atomic<size_t> promotedSize_ = 0; 168 }; 169 } // namespace panda::ecmascript 170 #endif // ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H 171