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