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