14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include <atomic> 204514f5e3Sopenharmony_ci#include <memory> 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_ci#include "ecmascript/js_hclass.h" 234514f5e3Sopenharmony_ci#include "ecmascript/mem/heap.h" 244514f5e3Sopenharmony_ci#include "ecmascript/mem/object_xray.h" 254514f5e3Sopenharmony_ci#include "ecmascript/mem/region.h" 264514f5e3Sopenharmony_ci#include "ecmascript/mem/space.h" 274514f5e3Sopenharmony_ci#include "ecmascript/mem/tagged_object.h" 284514f5e3Sopenharmony_ci#include "ecmascript/mem/tlab_allocator.h" 294514f5e3Sopenharmony_ci#include "ecmascript/taskpool/task.h" 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h" 324514f5e3Sopenharmony_ci 334514f5e3Sopenharmony_cinamespace panda::ecmascript { 344514f5e3Sopenharmony_ciclass ParallelEvacuator { 354514f5e3Sopenharmony_cipublic: 364514f5e3Sopenharmony_ci explicit ParallelEvacuator(Heap *heap) : heap_(heap) {} 374514f5e3Sopenharmony_ci ~ParallelEvacuator() = default; 384514f5e3Sopenharmony_ci void Initialize(); 394514f5e3Sopenharmony_ci void Finalize(); 404514f5e3Sopenharmony_ci void Evacuate(); 414514f5e3Sopenharmony_ci 424514f5e3Sopenharmony_ci size_t GetPromotedSize() const 434514f5e3Sopenharmony_ci { 444514f5e3Sopenharmony_ci return promotedSize_; 454514f5e3Sopenharmony_ci } 464514f5e3Sopenharmony_ci 474514f5e3Sopenharmony_ci size_t GetEdenToYoungSize() const 484514f5e3Sopenharmony_ci { 494514f5e3Sopenharmony_ci return edenToYoungSize_; 504514f5e3Sopenharmony_ci } 514514f5e3Sopenharmony_ciprivate: 524514f5e3Sopenharmony_ci class EvacuationTask : public Task { 534514f5e3Sopenharmony_ci public: 544514f5e3Sopenharmony_ci EvacuationTask(int32_t id, uint32_t idOrder, ParallelEvacuator *evacuator); 554514f5e3Sopenharmony_ci ~EvacuationTask() override; 564514f5e3Sopenharmony_ci bool Run(uint32_t threadIndex) override; 574514f5e3Sopenharmony_ci 584514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(EvacuationTask); 594514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(EvacuationTask); 604514f5e3Sopenharmony_ci 614514f5e3Sopenharmony_ci private: 624514f5e3Sopenharmony_ci uint32_t idOrder_; 634514f5e3Sopenharmony_ci ParallelEvacuator *evacuator_; 644514f5e3Sopenharmony_ci TlabAllocator *allocator_ {nullptr}; 654514f5e3Sopenharmony_ci }; 664514f5e3Sopenharmony_ci 674514f5e3Sopenharmony_ci class UpdateReferenceTask : public Task { 684514f5e3Sopenharmony_ci public: 694514f5e3Sopenharmony_ci UpdateReferenceTask(int32_t id, ParallelEvacuator *evacuator) : Task(id), evacuator_(evacuator) {}; 704514f5e3Sopenharmony_ci ~UpdateReferenceTask() override = default; 714514f5e3Sopenharmony_ci 724514f5e3Sopenharmony_ci bool Run(uint32_t threadIndex) override; 734514f5e3Sopenharmony_ci 744514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(UpdateReferenceTask); 754514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(UpdateReferenceTask); 764514f5e3Sopenharmony_ci 774514f5e3Sopenharmony_ci private: 784514f5e3Sopenharmony_ci ParallelEvacuator *evacuator_; 794514f5e3Sopenharmony_ci }; 804514f5e3Sopenharmony_ci 814514f5e3Sopenharmony_ci class Workload { 824514f5e3Sopenharmony_ci public: 834514f5e3Sopenharmony_ci Workload(ParallelEvacuator *evacuator, Region *region) : evacuator_(evacuator), region_(region) {}; 844514f5e3Sopenharmony_ci virtual ~Workload() = default; 854514f5e3Sopenharmony_ci virtual bool Process(bool isMain) = 0; 864514f5e3Sopenharmony_ci inline Region *GetRegion() const 874514f5e3Sopenharmony_ci { 884514f5e3Sopenharmony_ci return region_; 894514f5e3Sopenharmony_ci } 904514f5e3Sopenharmony_ci 914514f5e3Sopenharmony_ci inline ParallelEvacuator *GetEvacuator() const 924514f5e3Sopenharmony_ci { 934514f5e3Sopenharmony_ci return evacuator_; 944514f5e3Sopenharmony_ci } 954514f5e3Sopenharmony_ci protected: 964514f5e3Sopenharmony_ci ParallelEvacuator *evacuator_; 974514f5e3Sopenharmony_ci Region *region_; 984514f5e3Sopenharmony_ci }; 994514f5e3Sopenharmony_ci 1004514f5e3Sopenharmony_ci class AcquireItem { 1014514f5e3Sopenharmony_ci public: 1024514f5e3Sopenharmony_ci AcquireItem() = default; 1034514f5e3Sopenharmony_ci AcquireItem(AcquireItem&& other) noexcept {(void)other;}; 1044514f5e3Sopenharmony_ci bool TryAcquire(); 1054514f5e3Sopenharmony_ci private: 1064514f5e3Sopenharmony_ci std::atomic<bool> acquire_{false}; 1074514f5e3Sopenharmony_ci }; 1084514f5e3Sopenharmony_ci 1094514f5e3Sopenharmony_ci class WorkloadSet { 1104514f5e3Sopenharmony_ci public: 1114514f5e3Sopenharmony_ci inline void Add(std::unique_ptr<Workload> workload); 1124514f5e3Sopenharmony_ci inline size_t GetWorkloadCount() const; 1134514f5e3Sopenharmony_ci inline bool HasRemaningWorkload() const; 1144514f5e3Sopenharmony_ci inline bool FetchSubAndCheckWorkloadCount(size_t finishedCount); 1154514f5e3Sopenharmony_ci void PrepareWorkloads(); 1164514f5e3Sopenharmony_ci std::optional<size_t> GetNextIndex(); 1174514f5e3Sopenharmony_ci std::unique_ptr<ParallelEvacuator::Workload> TryGetWorkload(size_t index); 1184514f5e3Sopenharmony_ci void Clear(); 1194514f5e3Sopenharmony_ci private: 1204514f5e3Sopenharmony_ci using WorkItem = std::pair<AcquireItem, std::unique_ptr<Workload>>; 1214514f5e3Sopenharmony_ci std::vector<WorkItem> workloads_; 1224514f5e3Sopenharmony_ci std::vector<size_t> indexList_; 1234514f5e3Sopenharmony_ci std::atomic<size_t> indexCursor_ = 0; 1244514f5e3Sopenharmony_ci std::atomic<size_t> remainingWorkloadNum_ = 0; 1254514f5e3Sopenharmony_ci }; 1264514f5e3Sopenharmony_ci 1274514f5e3Sopenharmony_ci class EvacuateWorkload : public Workload { 1284514f5e3Sopenharmony_ci public: 1294514f5e3Sopenharmony_ci EvacuateWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {} 1304514f5e3Sopenharmony_ci ~EvacuateWorkload() override = default; 1314514f5e3Sopenharmony_ci bool Process(bool isMain) override; 1324514f5e3Sopenharmony_ci }; 1334514f5e3Sopenharmony_ci 1344514f5e3Sopenharmony_ci class UpdateRSetWorkload : public Workload { 1354514f5e3Sopenharmony_ci public: 1364514f5e3Sopenharmony_ci UpdateRSetWorkload(ParallelEvacuator *evacuator, Region *region, bool isEdenGC) 1374514f5e3Sopenharmony_ci : Workload(evacuator, region), isEdenGC_(isEdenGC) {} 1384514f5e3Sopenharmony_ci ~UpdateRSetWorkload() override = default; 1394514f5e3Sopenharmony_ci bool Process(bool isMain) override; 1404514f5e3Sopenharmony_ci private: 1414514f5e3Sopenharmony_ci bool isEdenGC_; 1424514f5e3Sopenharmony_ci }; 1434514f5e3Sopenharmony_ci 1444514f5e3Sopenharmony_ci class UpdateNewToEdenRSetWorkload : public Workload { 1454514f5e3Sopenharmony_ci public: 1464514f5e3Sopenharmony_ci UpdateNewToEdenRSetWorkload(ParallelEvacuator *evacuator, Region *region) : Workload(evacuator, region) {} 1474514f5e3Sopenharmony_ci ~UpdateNewToEdenRSetWorkload() override = default; 1484514f5e3Sopenharmony_ci bool Process(bool isMain) override; 1494514f5e3Sopenharmony_ci }; 1504514f5e3Sopenharmony_ci 1514514f5e3Sopenharmony_ci class UpdateNewRegionWorkload : public Workload { 1524514f5e3Sopenharmony_ci public: 1534514f5e3Sopenharmony_ci UpdateNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC) 1544514f5e3Sopenharmony_ci : Workload(evacuator, region), isYoungGC_(isYoungGC) {} 1554514f5e3Sopenharmony_ci ~UpdateNewRegionWorkload() override = default; 1564514f5e3Sopenharmony_ci bool Process(bool isMain) override; 1574514f5e3Sopenharmony_ci private: 1584514f5e3Sopenharmony_ci bool isYoungGC_; 1594514f5e3Sopenharmony_ci }; 1604514f5e3Sopenharmony_ci 1614514f5e3Sopenharmony_ci class UpdateAndSweepNewRegionWorkload : public Workload { 1624514f5e3Sopenharmony_ci public: 1634514f5e3Sopenharmony_ci UpdateAndSweepNewRegionWorkload(ParallelEvacuator *evacuator, Region *region, bool isYoungGC) 1644514f5e3Sopenharmony_ci : Workload(evacuator, region), isYoungGC_(isYoungGC) {} 1654514f5e3Sopenharmony_ci ~UpdateAndSweepNewRegionWorkload() override = default; 1664514f5e3Sopenharmony_ci bool Process(bool isMain) override; 1674514f5e3Sopenharmony_ci private: 1684514f5e3Sopenharmony_ci bool isYoungGC_; 1694514f5e3Sopenharmony_ci }; 1704514f5e3Sopenharmony_ci 1714514f5e3Sopenharmony_ci template <typename WorkloadCallback> 1724514f5e3Sopenharmony_ci void DrainWorkloads(WorkloadSet &workloadSet, WorkloadCallback callback); 1734514f5e3Sopenharmony_ci 1744514f5e3Sopenharmony_ci std::unordered_set<JSTaggedType> &ArrayTrackInfoSet(uint32_t threadIndex) 1754514f5e3Sopenharmony_ci { 1764514f5e3Sopenharmony_ci return arrayTrackInfoSets_[threadIndex]; 1774514f5e3Sopenharmony_ci } 1784514f5e3Sopenharmony_ci 1794514f5e3Sopenharmony_ci TaggedObject* UpdateAddressAfterEvacation(TaggedObject *oldTrackInfo); 1804514f5e3Sopenharmony_ci 1814514f5e3Sopenharmony_ci void UpdateTrackInfo(); 1824514f5e3Sopenharmony_ci 1834514f5e3Sopenharmony_ci bool ProcessWorkloads(bool isMain = false); 1844514f5e3Sopenharmony_ci 1854514f5e3Sopenharmony_ci void EvacuateSpace(); 1864514f5e3Sopenharmony_ci bool EvacuateSpace(TlabAllocator *allocation, uint32_t threadIndex, uint32_t idOrder, bool isMain = false); 1874514f5e3Sopenharmony_ci void UpdateRecordWeakReferenceInParallel(uint32_t idOrder); 1884514f5e3Sopenharmony_ci void EvacuateRegion(TlabAllocator *allocator, Region *region, std::unordered_set<JSTaggedType> &trackSet); 1894514f5e3Sopenharmony_ci template<bool SetEdenObject> 1904514f5e3Sopenharmony_ci inline void SetObjectFieldRSet(TaggedObject *object, JSHClass *cls); 1914514f5e3Sopenharmony_ci template<bool SetEdenObject> 1924514f5e3Sopenharmony_ci inline void SetObjectRSet(ObjectSlot slot, Region *region); 1934514f5e3Sopenharmony_ci 1944514f5e3Sopenharmony_ci inline void UpdateLocalToShareRSet(TaggedObject *object, JSHClass *cls); 1954514f5e3Sopenharmony_ci inline void SetLocalToShareRSet(ObjectSlot slot, Region *region); 1964514f5e3Sopenharmony_ci 1974514f5e3Sopenharmony_ci inline bool IsWholeRegionEvacuate(Region *region); 1984514f5e3Sopenharmony_ci inline bool WholeRegionEvacuate(Region *region); 1994514f5e3Sopenharmony_ci void VerifyValue(TaggedObject *object, ObjectSlot slot); 2004514f5e3Sopenharmony_ci void VerifyHeapObject(TaggedObject *object); 2014514f5e3Sopenharmony_ci 2024514f5e3Sopenharmony_ci void UpdateReference(); 2034514f5e3Sopenharmony_ci void UpdateRoot(); 2044514f5e3Sopenharmony_ci void UpdateWeakReference(); 2054514f5e3Sopenharmony_ci void UpdateRecordWeakReference(); 2064514f5e3Sopenharmony_ci template<TriggerGCType gcType> 2074514f5e3Sopenharmony_ci void UpdateWeakReferenceOpt(); 2084514f5e3Sopenharmony_ci template<bool IsEdenGC> 2094514f5e3Sopenharmony_ci void UpdateRSet(Region *region); 2104514f5e3Sopenharmony_ci void UpdateNewToEdenRSetReference(Region *region); 2114514f5e3Sopenharmony_ci template<TriggerGCType gcType> 2124514f5e3Sopenharmony_ci void UpdateNewRegionReference(Region *region); 2134514f5e3Sopenharmony_ci template<TriggerGCType gcType> 2144514f5e3Sopenharmony_ci void UpdateAndSweepNewRegionReference(Region *region); 2154514f5e3Sopenharmony_ci template<TriggerGCType gcType> 2164514f5e3Sopenharmony_ci void UpdateNewObjectField(TaggedObject *object, JSHClass *cls); 2174514f5e3Sopenharmony_ci 2184514f5e3Sopenharmony_ci template<typename Callback> 2194514f5e3Sopenharmony_ci inline bool VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback); 2204514f5e3Sopenharmony_ci inline bool UpdateForwardedOldToNewObjectSlot(TaggedObject *object, ObjectSlot &slot, bool isWeak); 2214514f5e3Sopenharmony_ci template<bool IsEdenGC> 2224514f5e3Sopenharmony_ci inline bool UpdateOldToNewObjectSlot(ObjectSlot &slot); 2234514f5e3Sopenharmony_ci inline bool UpdateNewToEdenObjectSlot(ObjectSlot &slot); 2244514f5e3Sopenharmony_ci inline void UpdateObjectSlot(ObjectSlot &slot); 2254514f5e3Sopenharmony_ci template<TriggerGCType gcType> 2264514f5e3Sopenharmony_ci inline void UpdateObjectSlotOpt(ObjectSlot &slot); 2274514f5e3Sopenharmony_ci inline void UpdateWeakObjectSlot(TaggedObject *object, ObjectSlot &slot); 2284514f5e3Sopenharmony_ci template<TriggerGCType gcType> 2294514f5e3Sopenharmony_ci inline bool UpdateWeakObjectSlotOpt(JSTaggedValue value, ObjectSlot &slot); 2304514f5e3Sopenharmony_ci 2314514f5e3Sopenharmony_ci inline int CalculateEvacuationThreadNum(); 2324514f5e3Sopenharmony_ci inline int CalculateUpdateThreadNum(); 2334514f5e3Sopenharmony_ci void WaitFinished(); 2344514f5e3Sopenharmony_ci 2354514f5e3Sopenharmony_ci Heap *heap_; 2364514f5e3Sopenharmony_ci TlabAllocator *allocator_ {nullptr}; 2374514f5e3Sopenharmony_ci 2384514f5e3Sopenharmony_ci uintptr_t waterLine_ = 0; 2394514f5e3Sopenharmony_ci std::unordered_set<JSTaggedType> arrayTrackInfoSets_[MAX_TASKPOOL_THREAD_NUM + 1]; 2404514f5e3Sopenharmony_ci uint32_t evacuateTaskNum_ = 0; 2414514f5e3Sopenharmony_ci std::atomic_int parallel_ = 0; 2424514f5e3Sopenharmony_ci Mutex mutex_; 2434514f5e3Sopenharmony_ci ConditionVariable condition_; 2444514f5e3Sopenharmony_ci std::atomic<size_t> promotedSize_ = 0; 2454514f5e3Sopenharmony_ci std::atomic<size_t> edenToYoungSize_ = 0; 2464514f5e3Sopenharmony_ci WorkloadSet evacuateWorkloadSet_; 2474514f5e3Sopenharmony_ci WorkloadSet updateWorkloadSet_; 2484514f5e3Sopenharmony_ci}; 2494514f5e3Sopenharmony_ci} // namespace panda::ecmascript 2504514f5e3Sopenharmony_ci#endif // ECMASCRIPT_MEM_PARALLEL_EVACUATOR_H 251