• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "common_components/taskpool/task.h"
23 #include "ecmascript/js_hclass.h"
24 #include "ecmascript/mem/heap.h"
25 #include "ecmascript/mem/object_xray.h"
26 #include "ecmascript/mem/region.h"
27 #include "ecmascript/mem/space.h"
28 #include "ecmascript/mem/tagged_object.h"
29 #include "ecmascript/mem/tlab_allocator.h"
30 
31 #include "ecmascript/platform/mutex.h"
32 
33 namespace panda::ecmascript {
34 enum RegionEvacuateType {
35     REGION_NEW_TO_NEW,
36     REGION_NEW_TO_OLD,
37     OBJECT_EVACUATE,
38 };
39 class ParallelEvacuator {
40 public:
41     explicit ParallelEvacuator(Heap *heap);
42     ~ParallelEvacuator() = default;
43     void Initialize();
44     void Finalize();
45     void Evacuate();
46     void SweepNewToOldRegions();
47 
GetPromotedSize()48     size_t GetPromotedSize() const
49     {
50         return promotedSize_;
51     }
52 private:
53     class UpdateRootVisitor final : public RootVisitor {
54     public:
55         explicit UpdateRootVisitor(ParallelEvacuator *evacuator);
56         ~UpdateRootVisitor() = default;
57 
58         void VisitRoot([[maybe_unused]] Root type, ObjectSlot slot) override;
59         void VisitRangeRoot([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) override;
60         void VisitBaseAndDerivedRoot([[maybe_unused]] Root type, ObjectSlot base, ObjectSlot derived,
61                                      uintptr_t baseOldObject) override;
62     private:
63         ParallelEvacuator *evacuator_ {nullptr};
64     };
65 
66     class SetObjectFieldRSetVisitor final : public BaseObjectVisitor<SetObjectFieldRSetVisitor> {
67     public:
68         explicit SetObjectFieldRSetVisitor(ParallelEvacuator *evacuator);
69         ~SetObjectFieldRSetVisitor() = default;
70 
71         void VisitObjectRangeImpl(BaseObject *root, uintptr_t startAddr, uintptr_t endAddr,
72                                   VisitObjectArea area) override;
73     private:
74         ParallelEvacuator *evacuator_ {nullptr};
75     };
76 
77     template <TriggerGCType gcType, bool needUpdateLocalToShare>
78     class UpdateNewObjectFieldVisitor final :
79         public BaseObjectVisitor<UpdateNewObjectFieldVisitor<gcType, needUpdateLocalToShare>> {
80     public:
81         explicit UpdateNewObjectFieldVisitor(ParallelEvacuator *evacuator);
82         ~UpdateNewObjectFieldVisitor() = default;
83 
84         void VisitObjectRangeImpl(BaseObject *root, uintptr_t start, uintptr_t end, VisitObjectArea area) override;
85     private:
86         ParallelEvacuator *evacuator_ {nullptr};
87     };
88 
89     class EvacuationTask : public common::Task {
90     public:
91         EvacuationTask(int32_t id, uint32_t idOrder, ParallelEvacuator *evacuator);
92         ~EvacuationTask() override;
93         bool Run(uint32_t threadIndex) override;
94 
95         NO_COPY_SEMANTIC(EvacuationTask);
96         NO_MOVE_SEMANTIC(EvacuationTask);
97 
98     private:
99         uint32_t idOrder_;
100         ParallelEvacuator *evacuator_;
101         TlabAllocator *allocator_ {nullptr};
102     };
103 
104     class UpdateReferenceTask : public common::Task {
105     public:
UpdateReferenceTask(int32_t id,ParallelEvacuator * evacuator)106         UpdateReferenceTask(int32_t id, ParallelEvacuator *evacuator) : common::Task(id), evacuator_(evacuator) {}
107         ~UpdateReferenceTask() override = default;
108 
109         bool Run(uint32_t threadIndex) override;
110 
111         NO_COPY_SEMANTIC(UpdateReferenceTask);
112         NO_MOVE_SEMANTIC(UpdateReferenceTask);
113 
114     private:
115         ParallelEvacuator *evacuator_;
116     };
117 
118     class Workload {
119     public:
Workload(ParallelEvacuator * evacuator,Region * region)120         Workload(ParallelEvacuator *evacuator, Region *region) : evacuator_(evacuator), region_(region) {};
121         virtual ~Workload() = default;
122         virtual bool Process(bool isMain, uint32_t threadIndex) = 0;
GetRegion()123         inline Region *GetRegion() const
124         {
125             return region_;
126         }
127 
GetEvacuator()128         inline ParallelEvacuator *GetEvacuator() const
129         {
130             return evacuator_;
131         }
132     protected:
133         ParallelEvacuator *evacuator_;
134         Region *region_;
135     };
136 
137     class AcquireItem {
138     public:
139         AcquireItem() = default;
AcquireItem(AcquireItem && other)140         AcquireItem(AcquireItem&& other) noexcept {(void)other;};
141         bool TryAcquire();
142     private:
143         std::atomic<bool> acquire_{false};
144     };
145 
146     class WorkloadSet {
147     public:
148         inline void Add(std::unique_ptr<Workload> workload);
149         inline size_t GetWorkloadCount() const;
150         inline bool HasRemaningWorkload() const;
151         inline bool FetchSubAndCheckWorkloadCount(size_t finishedCount);
152         void PrepareWorkloads();
153         std::optional<size_t> GetNextIndex();
154         std::unique_ptr<ParallelEvacuator::Workload> TryGetWorkload(size_t index);
155         void Clear();
156     private:
157         using WorkItem = std::pair<AcquireItem, std::unique_ptr<Workload>>;
158         std::vector<WorkItem> workloads_;
159         std::vector<size_t> indexList_;
160         std::atomic<size_t> indexCursor_ = 0;
161         std::atomic<size_t> remainingWorkloadNum_ = 0;
162     };
163 
164     class EvacuateWorkload : public Workload {
165     public:
EvacuateWorkload(ParallelEvacuator * evacuator,Region * region)166         EvacuateWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {}
167         ~EvacuateWorkload() override = default;
168         bool Process(bool isMain, uint32_t threadIndex) override;
169     };
170 
171     class UpdateRSetWorkload : public Workload {
172     public:
UpdateRSetWorkload(ParallelEvacuator * evacuator,Region * region)173         UpdateRSetWorkload(ParallelEvacuator *evacuator, Region *region)
174             : Workload(evacuator, region) {}
175         ~UpdateRSetWorkload() override = default;
176         bool Process(bool isMain, uint32_t threadIndex) override;
177     };
178 
179     class UpdateNewRegionWorkload : public Workload {
180     public:
UpdateNewRegionWorkload(ParallelEvacuator * evacuator,Region * region,bool isYoungGC)181         UpdateNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC)
182             : Workload(evacuator, region), isYoungGC_(isYoungGC) {}
183         ~UpdateNewRegionWorkload() override = default;
184         bool Process(bool isMain, uint32_t threadIndex) override;
185     private:
186         bool isYoungGC_;
187     };
188 
189     class UpdateAndSweepNewRegionWorkload : public Workload {
190     public:
UpdateAndSweepNewRegionWorkload(ParallelEvacuator * evacuator,Region * region,bool isYoungGC)191         UpdateAndSweepNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC)
192             : Workload(evacuator, region), isYoungGC_(isYoungGC) {}
193         ~UpdateAndSweepNewRegionWorkload() override = default;
194         bool Process(bool isMain, uint32_t threadIndex) override;
195     private:
196         bool isYoungGC_;
197     };
198 
199     class UpdateNewToOldEvacuationWorkload : public Workload {
200     public:
UpdateNewToOldEvacuationWorkload(ParallelEvacuator * evacuator,Region * region,bool isYoungGC)201         UpdateNewToOldEvacuationWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC)
202             : Workload(evacuator, region), isYoungGC_(isYoungGC) {}
203         ~UpdateNewToOldEvacuationWorkload() override = default;
204         bool Process(bool isMain, uint32_t threadIndex) override;
205     private:
206         bool isYoungGC_;
207     };
208 
209     template <typename WorkloadCallback>
210     void DrainWorkloads(WorkloadSet &workloadSet, WorkloadCallback callback);
211 
ArrayTrackInfoSet(uint32_t threadIndex)212     std::unordered_set<JSTaggedType> &ArrayTrackInfoSet(uint32_t threadIndex)
213     {
214         return arrayTrackInfoSets_[threadIndex];
215     }
216 
217     TaggedObject* UpdateAddressAfterEvacation(TaggedObject *oldTrackInfo);
218 
219     void UpdateTrackInfo();
220 
221     bool ProcessWorkloads(bool isMain = false, uint32_t threadIndex = 0);
222 
223     void EvacuateSpace();
224     bool EvacuateSpace(TlabAllocator *allocation, uint32_t threadIndex, uint32_t idOrder, bool isMain = false);
225     void UpdateRecordWeakReferenceInParallel(uint32_t idOrder);
226     void UpdateRecordWeakReference(uint32_t threadId);
227     template <TriggerGCType gcType>
228     void UpdateRecordJSWeakMap(uint32_t threadId);
229     void EvacuateRegion(TlabAllocator *allocator, Region *region, std::unordered_set<JSTaggedType> &trackSet);
230     inline void SetObjectFieldRSet(TaggedObject *object, JSHClass *cls);
231     inline void SetObjectRSet(ObjectSlot slot, Region *region);
232 
233     void ProcessFromSpaceEvacuation();
234     inline RegionEvacuateType SelectRegionEvacuateType(Region *region);
235     inline bool TryWholeRegionEvacuate(Region *region, RegionEvacuateType type);
236     inline void CompensateOvershootSizeIfHighAliveRate(Region* region);
237     void VerifyValue(TaggedObject *object, ObjectSlot slot);
238     void VerifyHeapObject(TaggedObject *object);
239 
240     void UpdateReference();
241     void UpdateRoot();
242     template<TriggerGCType gcType>
243     void UpdateWeakReferenceOpt();
244     void UpdateRSet(Region *region);
245     template<TriggerGCType gcType, bool needUpdateLocalToShare>
246     void UpdateNewRegionReference(Region *region);
247     template<TriggerGCType gcType, bool needUpdateLocalToShare>
248     void UpdateAndSweepNewRegionReference(Region *region);
249     template<TriggerGCType gcType, bool needUpdateLocalToShare>
250     void UpdateNewObjectField(TaggedObject *object, JSHClass *cls,
251         UpdateNewObjectFieldVisitor<gcType, needUpdateLocalToShare> &updateFieldVisito);
252     template<TriggerGCType gcType>
253     void UpdateNewToOldEvacuationReference(Region *region, uint32_t threadIndex);
254 
255     inline bool UpdateForwardedOldToNewObjectSlot(TaggedObject *object, ObjectSlot &slot, bool isWeak);
256     inline bool UpdateOldToNewObjectSlot(ObjectSlot &slot);
257     inline void UpdateObjectSlot(ObjectSlot &slot);
258     inline void UpdateWeakObjectSlot(TaggedObject *object, ObjectSlot &slot);
259     inline void UpdateCrossRegionObjectSlot(ObjectSlot &slot);
260     template<TriggerGCType gcType, bool needUpdateLocalToShare>
261     inline void UpdateNewObjectSlot(ObjectSlot &slot);
262     inline void UpdateObjectSlotValue(JSTaggedValue value, ObjectSlot &slot);
263 
264     inline int CalculateEvacuationThreadNum();
265     inline int CalculateUpdateThreadNum();
266     void WaitFinished();
267 
268     Heap *heap_;
269     UpdateRootVisitor updateRootVisitor_;
270     SetObjectFieldRSetVisitor setObjectFieldRSetVisitor_;
271     TlabAllocator *allocator_ {nullptr};
272 
273     uintptr_t waterLine_ = 0;
274     std::unordered_set<JSTaggedType> arrayTrackInfoSets_[common::MAX_TASKPOOL_THREAD_NUM + 1];
275     bool hasNewToOldRegions_ {false};
276     uint32_t evacuateTaskNum_ = 0;
277     std::atomic_int parallel_ = 0;
278     Mutex mutex_;
279     ConditionVariable condition_;
280     std::atomic<size_t> promotedSize_ = 0;
281     WorkloadSet evacuateWorkloadSet_;
282     WorkloadSet updateWorkloadSet_;
283 
284     template<TriggerGCType gcType>
285     friend class SlotUpdateRangeVisitor;
286 };
287 }  // namespace panda::ecmascript
288 #endif  // ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H
289