14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2022 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#include "ecmascript/mem/parallel_evacuator-inl.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/mem/tlab_allocator-inl.h"
194514f5e3Sopenharmony_ci#include "ecmascript/runtime_call_id.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cinamespace panda::ecmascript {
224514f5e3Sopenharmony_civoid ParallelEvacuator::Initialize()
234514f5e3Sopenharmony_ci{
244514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), ParallelEvacuatorInitialize);
254514f5e3Sopenharmony_ci    waterLine_ = heap_->GetNewSpace()->GetWaterLine();
264514f5e3Sopenharmony_ci    if (heap_->IsEdenMark()) {
274514f5e3Sopenharmony_ci        heap_->ReleaseEdenAllocator();
284514f5e3Sopenharmony_ci    } else {
294514f5e3Sopenharmony_ci        ASSERT(heap_->IsYoungMark() || heap_->IsFullMark());
304514f5e3Sopenharmony_ci        heap_->SwapNewSpace();
314514f5e3Sopenharmony_ci    }
324514f5e3Sopenharmony_ci    allocator_ = new TlabAllocator(heap_);
334514f5e3Sopenharmony_ci    promotedSize_ = 0;
344514f5e3Sopenharmony_ci    edenToYoungSize_ = 0;
354514f5e3Sopenharmony_ci}
364514f5e3Sopenharmony_ci
374514f5e3Sopenharmony_civoid ParallelEvacuator::Finalize()
384514f5e3Sopenharmony_ci{
394514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), ParallelEvacuatorFinalize);
404514f5e3Sopenharmony_ci    delete allocator_;
414514f5e3Sopenharmony_ci    evacuateWorkloadSet_.Clear();
424514f5e3Sopenharmony_ci    updateWorkloadSet_.Clear();
434514f5e3Sopenharmony_ci}
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_civoid ParallelEvacuator::Evacuate()
464514f5e3Sopenharmony_ci{
474514f5e3Sopenharmony_ci    Initialize();
484514f5e3Sopenharmony_ci    EvacuateSpace();
494514f5e3Sopenharmony_ci    UpdateReference();
504514f5e3Sopenharmony_ci    Finalize();
514514f5e3Sopenharmony_ci}
524514f5e3Sopenharmony_ci
534514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateTrackInfo()
544514f5e3Sopenharmony_ci{
554514f5e3Sopenharmony_ci    for (uint32_t i = 0; i <= MAX_TASKPOOL_THREAD_NUM; i++) {
564514f5e3Sopenharmony_ci        auto &trackInfoSet = ArrayTrackInfoSet(i);
574514f5e3Sopenharmony_ci        for (auto &each : trackInfoSet) {
584514f5e3Sopenharmony_ci            auto trackInfoVal = JSTaggedValue(each);
594514f5e3Sopenharmony_ci            if (!trackInfoVal.IsHeapObject() || !trackInfoVal.IsWeak()) {
604514f5e3Sopenharmony_ci                continue;
614514f5e3Sopenharmony_ci            }
624514f5e3Sopenharmony_ci            auto trackInfo = trackInfoVal.GetWeakReferentUnChecked();
634514f5e3Sopenharmony_ci            trackInfo = UpdateAddressAfterEvacation(trackInfo);
644514f5e3Sopenharmony_ci            if (trackInfo) {
654514f5e3Sopenharmony_ci                heap_->GetEcmaVM()->GetPGOProfiler()->UpdateTrackSpaceFlag(trackInfo, RegionSpaceFlag::IN_OLD_SPACE);
664514f5e3Sopenharmony_ci            }
674514f5e3Sopenharmony_ci        }
684514f5e3Sopenharmony_ci        trackInfoSet.clear();
694514f5e3Sopenharmony_ci    }
704514f5e3Sopenharmony_ci}
714514f5e3Sopenharmony_ci
724514f5e3Sopenharmony_civoid ParallelEvacuator::EvacuateSpace()
734514f5e3Sopenharmony_ci{
744514f5e3Sopenharmony_ci    TRACE_GC(GCStats::Scope::ScopeId::EvacuateSpace, heap_->GetEcmaVM()->GetEcmaGCStats());
754514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::EvacuateSpace");
764514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), ParallelEvacuator);
774514f5e3Sopenharmony_ci    auto &workloadSet = evacuateWorkloadSet_;
784514f5e3Sopenharmony_ci    if (heap_->IsEdenMark()) {
794514f5e3Sopenharmony_ci        heap_->GetEdenSpace()->EnumerateRegions([this, &workloadSet](Region *current) {
804514f5e3Sopenharmony_ci            workloadSet.Add(std::make_unique<EvacuateWorkload>(this, current));
814514f5e3Sopenharmony_ci        });
824514f5e3Sopenharmony_ci    } else if (heap_->IsConcurrentFullMark() || heap_->IsYoungMark()) {
834514f5e3Sopenharmony_ci        heap_->GetEdenSpace()->EnumerateRegions([this, &workloadSet](Region *current) {
844514f5e3Sopenharmony_ci            workloadSet.Add(std::make_unique<EvacuateWorkload>(this, current));
854514f5e3Sopenharmony_ci        });
864514f5e3Sopenharmony_ci        heap_->GetFromSpaceDuringEvacuation()->EnumerateRegions([this, &workloadSet](Region *current) {
874514f5e3Sopenharmony_ci            workloadSet.Add(std::make_unique<EvacuateWorkload>(this, current));
884514f5e3Sopenharmony_ci        });
894514f5e3Sopenharmony_ci        heap_->GetOldSpace()->EnumerateCollectRegionSet([this, &workloadSet](Region *current) {
904514f5e3Sopenharmony_ci            workloadSet.Add(std::make_unique<EvacuateWorkload>(this, current));
914514f5e3Sopenharmony_ci        });
924514f5e3Sopenharmony_ci    }
934514f5e3Sopenharmony_ci    workloadSet.PrepareWorkloads();
944514f5e3Sopenharmony_ci    if (heap_->IsParallelGCEnabled()) {
954514f5e3Sopenharmony_ci        LockHolder holder(mutex_);
964514f5e3Sopenharmony_ci        parallel_ = CalculateEvacuationThreadNum();
974514f5e3Sopenharmony_ci        ASSERT(parallel_ >= 0);
984514f5e3Sopenharmony_ci        evacuateTaskNum_ = static_cast<uint32_t>(parallel_);
994514f5e3Sopenharmony_ci        for (uint32_t i = 1; i <= evacuateTaskNum_; i++) {
1004514f5e3Sopenharmony_ci            Taskpool::GetCurrentTaskpool()->PostTask(
1014514f5e3Sopenharmony_ci                std::make_unique<EvacuationTask>(heap_->GetJSThread()->GetThreadId(), i, this));
1024514f5e3Sopenharmony_ci        }
1034514f5e3Sopenharmony_ci    } else {
1044514f5e3Sopenharmony_ci        evacuateTaskNum_ = 0;
1054514f5e3Sopenharmony_ci    }
1064514f5e3Sopenharmony_ci    {
1074514f5e3Sopenharmony_ci        GCStats::Scope sp2(GCStats::Scope::ScopeId::EvacuateRegion, heap_->GetEcmaVM()->GetEcmaGCStats());
1084514f5e3Sopenharmony_ci        EvacuateSpace(allocator_, MAIN_THREAD_INDEX, 0, true);
1094514f5e3Sopenharmony_ci    }
1104514f5e3Sopenharmony_ci
1114514f5e3Sopenharmony_ci    {
1124514f5e3Sopenharmony_ci        GCStats::Scope sp2(GCStats::Scope::ScopeId::WaitFinish, heap_->GetEcmaVM()->GetEcmaGCStats());
1134514f5e3Sopenharmony_ci        WaitFinished();
1144514f5e3Sopenharmony_ci    }
1154514f5e3Sopenharmony_ci
1164514f5e3Sopenharmony_ci    if (heap_->GetJSThread()->IsPGOProfilerEnable()) {
1174514f5e3Sopenharmony_ci        UpdateTrackInfo();
1184514f5e3Sopenharmony_ci    }
1194514f5e3Sopenharmony_ci}
1204514f5e3Sopenharmony_ci
1214514f5e3Sopenharmony_cibool ParallelEvacuator::EvacuateSpace(TlabAllocator *allocator, uint32_t threadIndex, uint32_t idOrder, bool isMain)
1224514f5e3Sopenharmony_ci{
1234514f5e3Sopenharmony_ci    UpdateRecordWeakReferenceInParallel(idOrder);
1244514f5e3Sopenharmony_ci
1254514f5e3Sopenharmony_ci    auto &arrayTrackInfoSet = ArrayTrackInfoSet(threadIndex);
1264514f5e3Sopenharmony_ci    DrainWorkloads(evacuateWorkloadSet_, [&](std::unique_ptr<Workload> &region) {
1274514f5e3Sopenharmony_ci        EvacuateRegion(allocator, region->GetRegion(), arrayTrackInfoSet);
1284514f5e3Sopenharmony_ci    });
1294514f5e3Sopenharmony_ci    allocator->Finalize();
1304514f5e3Sopenharmony_ci    if (!isMain) {
1314514f5e3Sopenharmony_ci        LockHolder holder(mutex_);
1324514f5e3Sopenharmony_ci        if (--parallel_ <= 0) {
1334514f5e3Sopenharmony_ci            condition_.SignalAll();
1344514f5e3Sopenharmony_ci        }
1354514f5e3Sopenharmony_ci    }
1364514f5e3Sopenharmony_ci    return true;
1374514f5e3Sopenharmony_ci}
1384514f5e3Sopenharmony_ci
1394514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateRecordWeakReferenceInParallel(uint32_t idOrder)
1404514f5e3Sopenharmony_ci{
1414514f5e3Sopenharmony_ci    auto totalThreadCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1;
1424514f5e3Sopenharmony_ci    for (uint32_t i = idOrder; i < totalThreadCount; i += (evacuateTaskNum_ + 1)) {
1434514f5e3Sopenharmony_ci        ProcessQueue *queue = heap_->GetWorkManager()->GetWeakReferenceQueue(i);
1444514f5e3Sopenharmony_ci        while (true) {
1454514f5e3Sopenharmony_ci            auto obj = queue->PopBack();
1464514f5e3Sopenharmony_ci            if (UNLIKELY(obj == nullptr)) {
1474514f5e3Sopenharmony_ci                break;
1484514f5e3Sopenharmony_ci            }
1494514f5e3Sopenharmony_ci            ObjectSlot slot(ToUintPtr(obj));
1504514f5e3Sopenharmony_ci            JSTaggedType value = slot.GetTaggedType();
1514514f5e3Sopenharmony_ci            if (JSTaggedValue(value).IsWeak()) {
1524514f5e3Sopenharmony_ci                ASSERT(heap_->IsConcurrentFullMark());
1534514f5e3Sopenharmony_ci                Region *objectRegion = Region::ObjectAddressToRange(value);
1544514f5e3Sopenharmony_ci                if (!objectRegion->InGeneralNewSpaceOrCSet() && !objectRegion->InSharedHeap() &&
1554514f5e3Sopenharmony_ci                        (objectRegion->GetMarkGCBitset() == nullptr || !objectRegion->Test(value))) {
1564514f5e3Sopenharmony_ci                    slot.Clear();
1574514f5e3Sopenharmony_ci                }
1584514f5e3Sopenharmony_ci            }
1594514f5e3Sopenharmony_ci        }
1604514f5e3Sopenharmony_ci    }
1614514f5e3Sopenharmony_ci}
1624514f5e3Sopenharmony_ci
1634514f5e3Sopenharmony_civoid ParallelEvacuator::EvacuateRegion(TlabAllocator *allocator, Region *region,
1644514f5e3Sopenharmony_ci                                       std::unordered_set<JSTaggedType> &trackSet)
1654514f5e3Sopenharmony_ci{
1664514f5e3Sopenharmony_ci    bool isInEden = region->InEdenSpace();
1674514f5e3Sopenharmony_ci    bool isInOldGen = region->InOldSpace();
1684514f5e3Sopenharmony_ci    bool isBelowAgeMark = region->BelowAgeMark();
1694514f5e3Sopenharmony_ci    bool pgoEnabled = heap_->GetJSThread()->IsPGOProfilerEnable();
1704514f5e3Sopenharmony_ci    bool inHeapProfiler = heap_->InHeapProfiler();
1714514f5e3Sopenharmony_ci    size_t promotedSize = 0;
1724514f5e3Sopenharmony_ci    size_t edenToYoungSize = 0;
1734514f5e3Sopenharmony_ci    if (WholeRegionEvacuate(region)) {
1744514f5e3Sopenharmony_ci        return;
1754514f5e3Sopenharmony_ci    }
1764514f5e3Sopenharmony_ci    region->IterateAllMarkedBits([this, &region, &isInOldGen, &isBelowAgeMark, isInEden, &pgoEnabled,
1774514f5e3Sopenharmony_ci                                  &promotedSize, &allocator, &trackSet, &edenToYoungSize, inHeapProfiler](void *mem) {
1784514f5e3Sopenharmony_ci        ASSERT(region->InRange(ToUintPtr(mem)));
1794514f5e3Sopenharmony_ci        auto header = reinterpret_cast<TaggedObject *>(mem);
1804514f5e3Sopenharmony_ci        auto klass = header->GetClass();
1814514f5e3Sopenharmony_ci        auto size = klass->SizeFromJSHClass(header);
1824514f5e3Sopenharmony_ci
1834514f5e3Sopenharmony_ci        uintptr_t address = 0;
1844514f5e3Sopenharmony_ci        bool actualPromoted = false;
1854514f5e3Sopenharmony_ci        bool hasAgeMark = isBelowAgeMark || (region->HasAgeMark() && ToUintPtr(mem) < waterLine_);
1864514f5e3Sopenharmony_ci        if (hasAgeMark) {
1874514f5e3Sopenharmony_ci            address = allocator->Allocate(size, OLD_SPACE);
1884514f5e3Sopenharmony_ci            actualPromoted = true;
1894514f5e3Sopenharmony_ci            promotedSize += size;
1904514f5e3Sopenharmony_ci        } else if (isInOldGen) {
1914514f5e3Sopenharmony_ci            address = allocator->Allocate(size, OLD_SPACE);
1924514f5e3Sopenharmony_ci            actualPromoted = true;
1934514f5e3Sopenharmony_ci        } else {
1944514f5e3Sopenharmony_ci            address = allocator->Allocate(size, SEMI_SPACE);
1954514f5e3Sopenharmony_ci            if (address == 0) {
1964514f5e3Sopenharmony_ci                address = allocator->Allocate(size, OLD_SPACE);
1974514f5e3Sopenharmony_ci                actualPromoted = true;
1984514f5e3Sopenharmony_ci                promotedSize += size;
1994514f5e3Sopenharmony_ci            } else if (isInEden) {
2004514f5e3Sopenharmony_ci                edenToYoungSize += size;
2014514f5e3Sopenharmony_ci            }
2024514f5e3Sopenharmony_ci        }
2034514f5e3Sopenharmony_ci        LOG_ECMA_IF(address == 0, FATAL) << "Evacuate object failed:" << size;
2044514f5e3Sopenharmony_ci
2054514f5e3Sopenharmony_ci        if (memcpy_s(ToVoidPtr(address), size, ToVoidPtr(ToUintPtr(mem)), size) != EOK) { // LOCV_EXCL_BR_LINE
2064514f5e3Sopenharmony_ci            LOG_FULL(FATAL) << "memcpy_s failed";
2074514f5e3Sopenharmony_ci        }
2084514f5e3Sopenharmony_ci        if (inHeapProfiler) {
2094514f5e3Sopenharmony_ci            heap_->OnMoveEvent(reinterpret_cast<uintptr_t>(mem), reinterpret_cast<TaggedObject *>(address), size);
2104514f5e3Sopenharmony_ci        }
2114514f5e3Sopenharmony_ci        if (pgoEnabled) {
2124514f5e3Sopenharmony_ci            if (actualPromoted && klass->IsJSArray()) {
2134514f5e3Sopenharmony_ci                auto trackInfo = JSArray::Cast(header)->GetTrackInfo();
2144514f5e3Sopenharmony_ci                trackSet.emplace(trackInfo.GetRawData());
2154514f5e3Sopenharmony_ci            }
2164514f5e3Sopenharmony_ci        }
2174514f5e3Sopenharmony_ci        Barriers::SetPrimitive(header, 0, MarkWord::FromForwardingAddress(address));
2184514f5e3Sopenharmony_ci
2194514f5e3Sopenharmony_ci        if (actualPromoted) {
2204514f5e3Sopenharmony_ci            SetObjectFieldRSet<false>(reinterpret_cast<TaggedObject *>(address), klass);
2214514f5e3Sopenharmony_ci        } else if (isInEden) {
2224514f5e3Sopenharmony_ci            SetObjectFieldRSet<true>(reinterpret_cast<TaggedObject *>(address), klass);
2234514f5e3Sopenharmony_ci        } else if (region->HasLocalToShareRememberedSet()) {
2244514f5e3Sopenharmony_ci            UpdateLocalToShareRSet(reinterpret_cast<TaggedObject *>(address), klass);
2254514f5e3Sopenharmony_ci        }
2264514f5e3Sopenharmony_ci    });
2274514f5e3Sopenharmony_ci    promotedSize_.fetch_add(promotedSize);
2284514f5e3Sopenharmony_ci    edenToYoungSize_.fetch_add(edenToYoungSize);
2294514f5e3Sopenharmony_ci}
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateReference()
2324514f5e3Sopenharmony_ci{
2334514f5e3Sopenharmony_ci    TRACE_GC(GCStats::Scope::ScopeId::UpdateReference, heap_->GetEcmaVM()->GetEcmaGCStats());
2344514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), ParallelUpdateReference);
2354514f5e3Sopenharmony_ci    // Update reference pointers
2364514f5e3Sopenharmony_ci    uint32_t youngeRegionMoveCount = 0;
2374514f5e3Sopenharmony_ci    uint32_t youngeRegionCopyCount = 0;
2384514f5e3Sopenharmony_ci    uint32_t oldRegionCount = 0;
2394514f5e3Sopenharmony_ci    auto &workloadSet = updateWorkloadSet_;
2404514f5e3Sopenharmony_ci    if (heap_->IsEdenMark()) {
2414514f5e3Sopenharmony_ci        heap_->GetNewSpace()->EnumerateRegions([&]([[maybe_unused]] Region *current) {
2424514f5e3Sopenharmony_ci            workloadSet.Add(
2434514f5e3Sopenharmony_ci                std::make_unique<UpdateNewToEdenRSetWorkload>(this, current));
2444514f5e3Sopenharmony_ci        });
2454514f5e3Sopenharmony_ci    } else {
2464514f5e3Sopenharmony_ci        heap_->GetNewSpace()->EnumerateRegions([&](Region *current) {
2474514f5e3Sopenharmony_ci            if (current->InNewToNewSet()) {
2484514f5e3Sopenharmony_ci                workloadSet.Add(
2494514f5e3Sopenharmony_ci                    std::make_unique<UpdateAndSweepNewRegionWorkload>(
2504514f5e3Sopenharmony_ci                        this, current, heap_->IsYoungMark()));
2514514f5e3Sopenharmony_ci                youngeRegionMoveCount++;
2524514f5e3Sopenharmony_ci            } else {
2534514f5e3Sopenharmony_ci                workloadSet.Add(
2544514f5e3Sopenharmony_ci                    std::make_unique<UpdateNewRegionWorkload>(this, current, heap_->IsYoungMark()));
2554514f5e3Sopenharmony_ci                youngeRegionCopyCount++;
2564514f5e3Sopenharmony_ci            }
2574514f5e3Sopenharmony_ci        });
2584514f5e3Sopenharmony_ci    }
2594514f5e3Sopenharmony_ci    heap_->EnumerateOldSpaceRegions([this, &oldRegionCount, &workloadSet](Region *current) {
2604514f5e3Sopenharmony_ci        if (current->InCollectSet()) {
2614514f5e3Sopenharmony_ci            return;
2624514f5e3Sopenharmony_ci        }
2634514f5e3Sopenharmony_ci        workloadSet.Add(std::make_unique<UpdateRSetWorkload>(this, current, heap_->IsEdenMark()));
2644514f5e3Sopenharmony_ci        oldRegionCount++;
2654514f5e3Sopenharmony_ci    });
2664514f5e3Sopenharmony_ci    heap_->EnumerateSnapshotSpaceRegions([this, &workloadSet](Region *current) {
2674514f5e3Sopenharmony_ci        workloadSet.Add(std::make_unique<UpdateRSetWorkload>(this, current, heap_->IsEdenMark()));
2684514f5e3Sopenharmony_ci    });
2694514f5e3Sopenharmony_ci    workloadSet.PrepareWorkloads();
2704514f5e3Sopenharmony_ci    LOG_GC(DEBUG) << "UpdatePointers statistic: younge space region compact moving count:"
2714514f5e3Sopenharmony_ci                        << youngeRegionMoveCount
2724514f5e3Sopenharmony_ci                        << "younge space region compact coping count:" << youngeRegionCopyCount
2734514f5e3Sopenharmony_ci                        << "old space region count:" << oldRegionCount;
2744514f5e3Sopenharmony_ci
2754514f5e3Sopenharmony_ci    if (heap_->IsParallelGCEnabled()) {
2764514f5e3Sopenharmony_ci        LockHolder holder(mutex_);
2774514f5e3Sopenharmony_ci        parallel_ = CalculateUpdateThreadNum();
2784514f5e3Sopenharmony_ci        for (int i = 0; i < parallel_; i++) {
2794514f5e3Sopenharmony_ci            Taskpool::GetCurrentTaskpool()->PostTask(
2804514f5e3Sopenharmony_ci                std::make_unique<UpdateReferenceTask>(heap_->GetJSThread()->GetThreadId(), this));
2814514f5e3Sopenharmony_ci        }
2824514f5e3Sopenharmony_ci    }
2834514f5e3Sopenharmony_ci    {
2844514f5e3Sopenharmony_ci        GCStats::Scope sp2(GCStats::Scope::ScopeId::UpdateRoot, heap_->GetEcmaVM()->GetEcmaGCStats());
2854514f5e3Sopenharmony_ci        UpdateRoot();
2864514f5e3Sopenharmony_ci    }
2874514f5e3Sopenharmony_ci
2884514f5e3Sopenharmony_ci    {
2894514f5e3Sopenharmony_ci        GCStats::Scope sp2(GCStats::Scope::ScopeId::UpdateWeekRef, heap_->GetEcmaVM()->GetEcmaGCStats());
2904514f5e3Sopenharmony_ci        if (heap_->IsEdenMark()) {
2914514f5e3Sopenharmony_ci            UpdateWeakReferenceOpt<TriggerGCType::EDEN_GC>();
2924514f5e3Sopenharmony_ci        } else if (heap_->IsYoungMark()) {
2934514f5e3Sopenharmony_ci            UpdateWeakReferenceOpt<TriggerGCType::YOUNG_GC>();
2944514f5e3Sopenharmony_ci        } else {
2954514f5e3Sopenharmony_ci            UpdateWeakReferenceOpt<TriggerGCType::OLD_GC>();
2964514f5e3Sopenharmony_ci        }
2974514f5e3Sopenharmony_ci    }
2984514f5e3Sopenharmony_ci    {
2994514f5e3Sopenharmony_ci        GCStats::Scope sp2(GCStats::Scope::ScopeId::ProceeWorkload, heap_->GetEcmaVM()->GetEcmaGCStats());\
3004514f5e3Sopenharmony_ci        ProcessWorkloads(true);
3014514f5e3Sopenharmony_ci    }
3024514f5e3Sopenharmony_ci    WaitFinished();
3034514f5e3Sopenharmony_ci}
3044514f5e3Sopenharmony_ci
3054514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateRoot()
3064514f5e3Sopenharmony_ci{
3074514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), UpdateRoot);
3084514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::UpdateRoot");
3094514f5e3Sopenharmony_ci    RootVisitor gcUpdateYoung = [this]([[maybe_unused]] Root type, ObjectSlot slot) {
3104514f5e3Sopenharmony_ci        UpdateObjectSlot(slot);
3114514f5e3Sopenharmony_ci    };
3124514f5e3Sopenharmony_ci    RootRangeVisitor gcUpdateRangeYoung = [this]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) {
3134514f5e3Sopenharmony_ci        for (ObjectSlot slot = start; slot < end; slot++) {
3144514f5e3Sopenharmony_ci            UpdateObjectSlot(slot);
3154514f5e3Sopenharmony_ci        }
3164514f5e3Sopenharmony_ci    };
3174514f5e3Sopenharmony_ci    RootBaseAndDerivedVisitor gcUpdateDerived =
3184514f5e3Sopenharmony_ci        []([[maybe_unused]] Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject) {
3194514f5e3Sopenharmony_ci        if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) {
3204514f5e3Sopenharmony_ci            derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
3214514f5e3Sopenharmony_ci        }
3224514f5e3Sopenharmony_ci    };
3234514f5e3Sopenharmony_ci
3244514f5e3Sopenharmony_ci    ObjectXRay::VisitVMRoots(heap_->GetEcmaVM(), gcUpdateYoung, gcUpdateRangeYoung, gcUpdateDerived,
3254514f5e3Sopenharmony_ci                             VMRootVisitType::UPDATE_ROOT);
3264514f5e3Sopenharmony_ci}
3274514f5e3Sopenharmony_ci
3284514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateRecordWeakReference()
3294514f5e3Sopenharmony_ci{
3304514f5e3Sopenharmony_ci    auto totalThreadCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1;
3314514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < totalThreadCount; i++) {
3324514f5e3Sopenharmony_ci        ProcessQueue *queue = heap_->GetWorkManager()->GetWeakReferenceQueue(i);
3334514f5e3Sopenharmony_ci
3344514f5e3Sopenharmony_ci        while (true) {
3354514f5e3Sopenharmony_ci            auto obj = queue->PopBack();
3364514f5e3Sopenharmony_ci            if (UNLIKELY(obj == nullptr)) {
3374514f5e3Sopenharmony_ci                break;
3384514f5e3Sopenharmony_ci            }
3394514f5e3Sopenharmony_ci            ObjectSlot slot(ToUintPtr(obj));
3404514f5e3Sopenharmony_ci            JSTaggedValue value(slot.GetTaggedType());
3414514f5e3Sopenharmony_ci            if (value.IsWeak()) {
3424514f5e3Sopenharmony_ci                UpdateWeakObjectSlot(value.GetTaggedWeakRef(), slot);
3434514f5e3Sopenharmony_ci            }
3444514f5e3Sopenharmony_ci        }
3454514f5e3Sopenharmony_ci    }
3464514f5e3Sopenharmony_ci}
3474514f5e3Sopenharmony_ci
3484514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateWeakReference()
3494514f5e3Sopenharmony_ci{
3504514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), UpdateWeakReference);
3514514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::UpdateWeakReference");
3524514f5e3Sopenharmony_ci    UpdateRecordWeakReference();
3534514f5e3Sopenharmony_ci    bool isFullMark = heap_->IsConcurrentFullMark();
3544514f5e3Sopenharmony_ci    bool isEdenMark = heap_->IsEdenMark();
3554514f5e3Sopenharmony_ci    WeakRootVisitor gcUpdateWeak = [isFullMark, isEdenMark](TaggedObject *header) -> TaggedObject* {
3564514f5e3Sopenharmony_ci        Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(header));
3574514f5e3Sopenharmony_ci        if (UNLIKELY(objectRegion == nullptr)) {
3584514f5e3Sopenharmony_ci            LOG_GC(ERROR) << "PartialGC updateWeakReference: region is nullptr, header is " << header;
3594514f5e3Sopenharmony_ci            return nullptr;
3604514f5e3Sopenharmony_ci        }
3614514f5e3Sopenharmony_ci        // The weak object in shared heap is always alive during partialGC.
3624514f5e3Sopenharmony_ci        if (objectRegion->InSharedHeap()) {
3634514f5e3Sopenharmony_ci            return header;
3644514f5e3Sopenharmony_ci        }
3654514f5e3Sopenharmony_ci        if (isEdenMark) {
3664514f5e3Sopenharmony_ci            if (!objectRegion->InEdenSpace()) {
3674514f5e3Sopenharmony_ci                return header;
3684514f5e3Sopenharmony_ci            }
3694514f5e3Sopenharmony_ci            MarkWord markWord(header);
3704514f5e3Sopenharmony_ci            if (markWord.IsForwardingAddress()) {
3714514f5e3Sopenharmony_ci                return markWord.ToForwardingAddress();
3724514f5e3Sopenharmony_ci            }
3734514f5e3Sopenharmony_ci            return nullptr;
3744514f5e3Sopenharmony_ci        }
3754514f5e3Sopenharmony_ci        if (objectRegion->InGeneralNewSpaceOrCSet()) {
3764514f5e3Sopenharmony_ci            if (objectRegion->InNewToNewSet()) {
3774514f5e3Sopenharmony_ci                if (objectRegion->Test(header)) {
3784514f5e3Sopenharmony_ci                    return header;
3794514f5e3Sopenharmony_ci                }
3804514f5e3Sopenharmony_ci            } else {
3814514f5e3Sopenharmony_ci                MarkWord markWord(header);
3824514f5e3Sopenharmony_ci                if (markWord.IsForwardingAddress()) {
3834514f5e3Sopenharmony_ci                    return markWord.ToForwardingAddress();
3844514f5e3Sopenharmony_ci                }
3854514f5e3Sopenharmony_ci            }
3864514f5e3Sopenharmony_ci            return nullptr;
3874514f5e3Sopenharmony_ci        }
3884514f5e3Sopenharmony_ci        if (isFullMark) {
3894514f5e3Sopenharmony_ci            if (objectRegion->GetMarkGCBitset() == nullptr || !objectRegion->Test(header)) {
3904514f5e3Sopenharmony_ci                return nullptr;
3914514f5e3Sopenharmony_ci            }
3924514f5e3Sopenharmony_ci        }
3934514f5e3Sopenharmony_ci        return header;
3944514f5e3Sopenharmony_ci    };
3954514f5e3Sopenharmony_ci
3964514f5e3Sopenharmony_ci    heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak);
3974514f5e3Sopenharmony_ci    heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak);
3984514f5e3Sopenharmony_ci    heap_->GetEcmaVM()->GetJSThread()->UpdateJitCodeMapReference(gcUpdateWeak);
3994514f5e3Sopenharmony_ci}
4004514f5e3Sopenharmony_ci
4014514f5e3Sopenharmony_citemplate<TriggerGCType gcType>
4024514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateWeakReferenceOpt()
4034514f5e3Sopenharmony_ci{
4044514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), UpdateWeakReference);
4054514f5e3Sopenharmony_ci    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::UpdateWeakReference");
4064514f5e3Sopenharmony_ci    WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) -> TaggedObject* {
4074514f5e3Sopenharmony_ci        Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(header));
4084514f5e3Sopenharmony_ci        ASSERT(objectRegion != nullptr);
4094514f5e3Sopenharmony_ci        if constexpr (gcType == TriggerGCType::EDEN_GC) {
4104514f5e3Sopenharmony_ci            if (!objectRegion->InEdenSpace()) {
4114514f5e3Sopenharmony_ci                return header;
4124514f5e3Sopenharmony_ci            }
4134514f5e3Sopenharmony_ci            MarkWord markWord(header);
4144514f5e3Sopenharmony_ci            if (markWord.IsForwardingAddress()) {
4154514f5e3Sopenharmony_ci                return markWord.ToForwardingAddress();
4164514f5e3Sopenharmony_ci            }
4174514f5e3Sopenharmony_ci            return nullptr;
4184514f5e3Sopenharmony_ci        } else if constexpr (gcType == TriggerGCType::YOUNG_GC) {
4194514f5e3Sopenharmony_ci            if (!objectRegion->InGeneralNewSpace()) {
4204514f5e3Sopenharmony_ci                return header;
4214514f5e3Sopenharmony_ci            }
4224514f5e3Sopenharmony_ci        } else if constexpr (gcType == TriggerGCType::OLD_GC) {
4234514f5e3Sopenharmony_ci            if (!objectRegion->InGeneralNewSpaceOrCSet()) {
4244514f5e3Sopenharmony_ci                if (!objectRegion->InSharedHeap() && (objectRegion->GetMarkGCBitset() == nullptr ||
4254514f5e3Sopenharmony_ci                                              !objectRegion->Test(header))) {
4264514f5e3Sopenharmony_ci                    return nullptr;
4274514f5e3Sopenharmony_ci                }
4284514f5e3Sopenharmony_ci                return header;
4294514f5e3Sopenharmony_ci            }
4304514f5e3Sopenharmony_ci        } else { // LOCV_EXCL_BR_LINE
4314514f5e3Sopenharmony_ci            LOG_GC(FATAL) << "WeakRootVisitor: not support gcType yet";
4324514f5e3Sopenharmony_ci            UNREACHABLE();
4334514f5e3Sopenharmony_ci        }
4344514f5e3Sopenharmony_ci        if (objectRegion->InNewToNewSet()) {
4354514f5e3Sopenharmony_ci            if (objectRegion->Test(header)) {
4364514f5e3Sopenharmony_ci                return header;
4374514f5e3Sopenharmony_ci            }
4384514f5e3Sopenharmony_ci        } else {
4394514f5e3Sopenharmony_ci            MarkWord markWord(header);
4404514f5e3Sopenharmony_ci            if (markWord.IsForwardingAddress()) {
4414514f5e3Sopenharmony_ci                return markWord.ToForwardingAddress();
4424514f5e3Sopenharmony_ci            }
4434514f5e3Sopenharmony_ci        }
4444514f5e3Sopenharmony_ci        return nullptr;
4454514f5e3Sopenharmony_ci    };
4464514f5e3Sopenharmony_ci
4474514f5e3Sopenharmony_ci    heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak);
4484514f5e3Sopenharmony_ci    heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak);
4494514f5e3Sopenharmony_ci    heap_->GetEcmaVM()->GetJSThread()->UpdateJitCodeMapReference(gcUpdateWeak);
4504514f5e3Sopenharmony_ci}
4514514f5e3Sopenharmony_ci
4524514f5e3Sopenharmony_citemplate<bool IsEdenGC>
4534514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateRSet(Region *region)
4544514f5e3Sopenharmony_ci{
4554514f5e3Sopenharmony_ci    auto cb = [this](void *mem) -> bool {
4564514f5e3Sopenharmony_ci        ObjectSlot slot(ToUintPtr(mem));
4574514f5e3Sopenharmony_ci        return UpdateOldToNewObjectSlot<IsEdenGC>(slot);
4584514f5e3Sopenharmony_ci    };
4594514f5e3Sopenharmony_ci
4604514f5e3Sopenharmony_ci    if (heap_->GetSweeper()->IsSweeping()) {
4614514f5e3Sopenharmony_ci        if (region->IsGCFlagSet(RegionGCFlags::HAS_BEEN_SWEPT)) {
4624514f5e3Sopenharmony_ci            // Region is safe while update remember set
4634514f5e3Sopenharmony_ci            region->MergeOldToNewRSetForCS();
4644514f5e3Sopenharmony_ci            region->MergeLocalToShareRSetForCS();
4654514f5e3Sopenharmony_ci        } else {
4664514f5e3Sopenharmony_ci            region->AtomicIterateAllSweepingRSetBits(cb);
4674514f5e3Sopenharmony_ci        }
4684514f5e3Sopenharmony_ci    }
4694514f5e3Sopenharmony_ci    region->IterateAllOldToNewBits(cb);
4704514f5e3Sopenharmony_ci    if (heap_->IsYoungMark()) {
4714514f5e3Sopenharmony_ci        return;
4724514f5e3Sopenharmony_ci    }
4734514f5e3Sopenharmony_ci    if constexpr (IsEdenGC) {
4744514f5e3Sopenharmony_ci        region->IterateAllCrossRegionBits([this](void *mem) {
4754514f5e3Sopenharmony_ci            ObjectSlot slot(ToUintPtr(mem));
4764514f5e3Sopenharmony_ci            UpdateObjectSlot(slot);
4774514f5e3Sopenharmony_ci        });
4784514f5e3Sopenharmony_ci    } else {
4794514f5e3Sopenharmony_ci        region->IterateAllCrossRegionBits([this](void *mem) {
4804514f5e3Sopenharmony_ci            ObjectSlot slot(ToUintPtr(mem));
4814514f5e3Sopenharmony_ci            JSTaggedType value = slot.GetTaggedType();
4824514f5e3Sopenharmony_ci            if (JSTaggedValue(value).IsHeapObject() && Region::ObjectAddressToRange(value)->InCollectSet()) {
4834514f5e3Sopenharmony_ci                UpdateObjectSlotOpt<TriggerGCType::OLD_GC>(slot);
4844514f5e3Sopenharmony_ci            }
4854514f5e3Sopenharmony_ci        });
4864514f5e3Sopenharmony_ci    }
4874514f5e3Sopenharmony_ci    region->DeleteCrossRegionRSet();
4884514f5e3Sopenharmony_ci}
4894514f5e3Sopenharmony_ci
4904514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateNewToEdenRSetReference(Region *region)
4914514f5e3Sopenharmony_ci{
4924514f5e3Sopenharmony_ci    auto cb = [this](void *mem) -> bool {
4934514f5e3Sopenharmony_ci        ObjectSlot slot(ToUintPtr(mem));
4944514f5e3Sopenharmony_ci        return UpdateNewToEdenObjectSlot(slot);
4954514f5e3Sopenharmony_ci    };
4964514f5e3Sopenharmony_ci    region->IterateAllNewToEdenBits(cb);
4974514f5e3Sopenharmony_ci    region->ClearNewToEdenRSet();
4984514f5e3Sopenharmony_ci}
4994514f5e3Sopenharmony_ci
5004514f5e3Sopenharmony_citemplate<TriggerGCType gcType>
5014514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateNewRegionReference(Region *region)
5024514f5e3Sopenharmony_ci{
5034514f5e3Sopenharmony_ci    Region *current = heap_->GetNewSpace()->GetCurrentRegion();
5044514f5e3Sopenharmony_ci    auto curPtr = region->GetBegin();
5054514f5e3Sopenharmony_ci    uintptr_t endPtr = 0;
5064514f5e3Sopenharmony_ci    if (region == current) {
5074514f5e3Sopenharmony_ci        auto top = heap_->GetNewSpace()->GetTop();
5084514f5e3Sopenharmony_ci        endPtr = curPtr + region->GetAllocatedBytes(top);
5094514f5e3Sopenharmony_ci    } else {
5104514f5e3Sopenharmony_ci        endPtr = curPtr + region->GetAllocatedBytes();
5114514f5e3Sopenharmony_ci    }
5124514f5e3Sopenharmony_ci
5134514f5e3Sopenharmony_ci    size_t objSize = 0;
5144514f5e3Sopenharmony_ci    while (curPtr < endPtr) {
5154514f5e3Sopenharmony_ci        auto freeObject = FreeObject::Cast(curPtr);
5164514f5e3Sopenharmony_ci        // If curPtr is freeObject, It must to mark unpoison first.
5174514f5e3Sopenharmony_ci        ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<void *>(freeObject), TaggedObject::TaggedObjectSize());
5184514f5e3Sopenharmony_ci        if (!freeObject->IsFreeObject()) {
5194514f5e3Sopenharmony_ci            auto obj = reinterpret_cast<TaggedObject *>(curPtr);
5204514f5e3Sopenharmony_ci            auto klass = obj->GetClass();
5214514f5e3Sopenharmony_ci            UpdateNewObjectField<gcType>(obj, klass);
5224514f5e3Sopenharmony_ci            objSize = klass->SizeFromJSHClass(obj);
5234514f5e3Sopenharmony_ci        } else {
5244514f5e3Sopenharmony_ci            freeObject->AsanUnPoisonFreeObject();
5254514f5e3Sopenharmony_ci            objSize = freeObject->Available();
5264514f5e3Sopenharmony_ci            freeObject->AsanPoisonFreeObject();
5274514f5e3Sopenharmony_ci        }
5284514f5e3Sopenharmony_ci        curPtr += objSize;
5294514f5e3Sopenharmony_ci        CHECK_OBJECT_SIZE(objSize);
5304514f5e3Sopenharmony_ci    }
5314514f5e3Sopenharmony_ci    CHECK_REGION_END(curPtr, endPtr);
5324514f5e3Sopenharmony_ci}
5334514f5e3Sopenharmony_ci
5344514f5e3Sopenharmony_citemplate<TriggerGCType gcType>
5354514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateAndSweepNewRegionReference(Region *region)
5364514f5e3Sopenharmony_ci{
5374514f5e3Sopenharmony_ci    uintptr_t freeStart = region->GetBegin();
5384514f5e3Sopenharmony_ci    uintptr_t freeEnd = freeStart + region->GetAllocatedBytes();
5394514f5e3Sopenharmony_ci    region->IterateAllMarkedBits([&](void *mem) {
5404514f5e3Sopenharmony_ci        ASSERT(region->InRange(ToUintPtr(mem)));
5414514f5e3Sopenharmony_ci        auto header = reinterpret_cast<TaggedObject *>(mem);
5424514f5e3Sopenharmony_ci        JSHClass *klass = header->GetClass();
5434514f5e3Sopenharmony_ci        UpdateNewObjectField<gcType>(header, klass);
5444514f5e3Sopenharmony_ci
5454514f5e3Sopenharmony_ci        uintptr_t freeEnd = ToUintPtr(mem);
5464514f5e3Sopenharmony_ci        if (freeStart != freeEnd) {
5474514f5e3Sopenharmony_ci            size_t freeSize = freeEnd - freeStart;
5484514f5e3Sopenharmony_ci            FreeObject::FillFreeObject(heap_, freeStart, freeSize);
5494514f5e3Sopenharmony_ci            region->ClearLocalToShareRSetInRange(freeStart, freeEnd);
5504514f5e3Sopenharmony_ci        }
5514514f5e3Sopenharmony_ci
5524514f5e3Sopenharmony_ci        freeStart = freeEnd + klass->SizeFromJSHClass(header);
5534514f5e3Sopenharmony_ci    });
5544514f5e3Sopenharmony_ci    CHECK_REGION_END(freeStart, freeEnd);
5554514f5e3Sopenharmony_ci    if (freeStart < freeEnd) {
5564514f5e3Sopenharmony_ci        FreeObject::FillFreeObject(heap_, freeStart, freeEnd - freeStart);
5574514f5e3Sopenharmony_ci        region->ClearLocalToShareRSetInRange(freeStart, freeEnd);
5584514f5e3Sopenharmony_ci    }
5594514f5e3Sopenharmony_ci}
5604514f5e3Sopenharmony_ci
5614514f5e3Sopenharmony_citemplate<TriggerGCType gcType>
5624514f5e3Sopenharmony_civoid ParallelEvacuator::UpdateNewObjectField(TaggedObject *object, JSHClass *cls)
5634514f5e3Sopenharmony_ci{
5644514f5e3Sopenharmony_ci    ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(object, cls,
5654514f5e3Sopenharmony_ci        [this](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) {
5664514f5e3Sopenharmony_ci            if (area == VisitObjectArea::IN_OBJECT) {
5674514f5e3Sopenharmony_ci                if (VisitBodyInObj(root, start, end,
5684514f5e3Sopenharmony_ci                                    [&](ObjectSlot slot) { UpdateObjectSlotOpt<gcType>(slot); })) {
5694514f5e3Sopenharmony_ci                    return;
5704514f5e3Sopenharmony_ci                };
5714514f5e3Sopenharmony_ci            }
5724514f5e3Sopenharmony_ci            for (ObjectSlot slot = start; slot < end; slot++) {
5734514f5e3Sopenharmony_ci                UpdateObjectSlotOpt<gcType>(slot);
5744514f5e3Sopenharmony_ci            }
5754514f5e3Sopenharmony_ci        });
5764514f5e3Sopenharmony_ci}
5774514f5e3Sopenharmony_ci
5784514f5e3Sopenharmony_civoid ParallelEvacuator::WaitFinished()
5794514f5e3Sopenharmony_ci{
5804514f5e3Sopenharmony_ci    MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), WaitUpdateFinished);
5814514f5e3Sopenharmony_ci    if (parallel_ > 0) {
5824514f5e3Sopenharmony_ci        LockHolder holder(mutex_);
5834514f5e3Sopenharmony_ci        while (parallel_ > 0) {
5844514f5e3Sopenharmony_ci            condition_.Wait(&mutex_);
5854514f5e3Sopenharmony_ci        }
5864514f5e3Sopenharmony_ci    }
5874514f5e3Sopenharmony_ci}
5884514f5e3Sopenharmony_ci
5894514f5e3Sopenharmony_cibool ParallelEvacuator::ProcessWorkloads(bool isMain)
5904514f5e3Sopenharmony_ci{
5914514f5e3Sopenharmony_ci    DrainWorkloads(updateWorkloadSet_, [&](std::unique_ptr<Workload> &region) {
5924514f5e3Sopenharmony_ci        region->Process(isMain);
5934514f5e3Sopenharmony_ci        });
5944514f5e3Sopenharmony_ci    if (!isMain) {
5954514f5e3Sopenharmony_ci        LockHolder holder(mutex_);
5964514f5e3Sopenharmony_ci        if (--parallel_ <= 0) {
5974514f5e3Sopenharmony_ci            condition_.SignalAll();
5984514f5e3Sopenharmony_ci        }
5994514f5e3Sopenharmony_ci    }
6004514f5e3Sopenharmony_ci    return true;
6014514f5e3Sopenharmony_ci}
6024514f5e3Sopenharmony_ci
6034514f5e3Sopenharmony_citemplate <typename WorkloadCallback>
6044514f5e3Sopenharmony_civoid ParallelEvacuator::DrainWorkloads(WorkloadSet &workloadSet, WorkloadCallback callback)
6054514f5e3Sopenharmony_ci{
6064514f5e3Sopenharmony_ci    std::unique_ptr<Workload> region;
6074514f5e3Sopenharmony_ci    while (workloadSet.HasRemaningWorkload()) {
6084514f5e3Sopenharmony_ci        std::optional<size_t> index = workloadSet.GetNextIndex();
6094514f5e3Sopenharmony_ci        if (!index.has_value()) {
6104514f5e3Sopenharmony_ci            return;
6114514f5e3Sopenharmony_ci        }
6124514f5e3Sopenharmony_ci        size_t count = workloadSet.GetWorkloadCount();
6134514f5e3Sopenharmony_ci        size_t finishedCount = 0;
6144514f5e3Sopenharmony_ci        for (size_t i = index.value(); i < count; i++) {
6154514f5e3Sopenharmony_ci            region = workloadSet.TryGetWorkload(i);
6164514f5e3Sopenharmony_ci            if (region == nullptr) {
6174514f5e3Sopenharmony_ci                break;
6184514f5e3Sopenharmony_ci            }
6194514f5e3Sopenharmony_ci            callback(region);
6204514f5e3Sopenharmony_ci            finishedCount++;
6214514f5e3Sopenharmony_ci        }
6224514f5e3Sopenharmony_ci        if (finishedCount && workloadSet.FetchSubAndCheckWorkloadCount(finishedCount)) {
6234514f5e3Sopenharmony_ci            return;
6244514f5e3Sopenharmony_ci        }
6254514f5e3Sopenharmony_ci    }
6264514f5e3Sopenharmony_ci}
6274514f5e3Sopenharmony_ci
6284514f5e3Sopenharmony_civoid ParallelEvacuator::WorkloadSet::PrepareWorkloads()
6294514f5e3Sopenharmony_ci{
6304514f5e3Sopenharmony_ci    size_t size = workloads_.size();
6314514f5e3Sopenharmony_ci    remainingWorkloadNum_.store(size, std::memory_order_relaxed);
6324514f5e3Sopenharmony_ci    /*
6334514f5e3Sopenharmony_ci    Construct indexList_ containing starting indices for multi-threaded acquire workload.
6344514f5e3Sopenharmony_ci    The construction method starts with the interval [0, size] and recursively
6354514f5e3Sopenharmony_ci    selects midpoints as starting indices for subintervals.
6364514f5e3Sopenharmony_ci    The first starting index is 0 to ensure no workloads are missed.
6374514f5e3Sopenharmony_ci    */
6384514f5e3Sopenharmony_ci    indexList_.reserve(size);
6394514f5e3Sopenharmony_ci    indexList_.emplace_back(0);
6404514f5e3Sopenharmony_ci    std::vector<std::pair<size_t, size_t>> pairList{{0, size}};
6414514f5e3Sopenharmony_ci    pairList.reserve(size);
6424514f5e3Sopenharmony_ci    while (!pairList.empty()) {
6434514f5e3Sopenharmony_ci        auto [start, end] = pairList.back();
6444514f5e3Sopenharmony_ci        pairList.pop_back();
6454514f5e3Sopenharmony_ci        size_t mid = (start + end) >> 1;
6464514f5e3Sopenharmony_ci        indexList_.emplace_back(mid);
6474514f5e3Sopenharmony_ci        if (end - mid > 1U) {
6484514f5e3Sopenharmony_ci            pairList.emplace_back(mid, end);
6494514f5e3Sopenharmony_ci        }
6504514f5e3Sopenharmony_ci        if (mid - start > 1U) {
6514514f5e3Sopenharmony_ci            pairList.emplace_back(start, mid);
6524514f5e3Sopenharmony_ci        }
6534514f5e3Sopenharmony_ci    }
6544514f5e3Sopenharmony_ci}
6554514f5e3Sopenharmony_ci
6564514f5e3Sopenharmony_cistd::optional<size_t> ParallelEvacuator::WorkloadSet::GetNextIndex()
6574514f5e3Sopenharmony_ci{
6584514f5e3Sopenharmony_ci    size_t cursor = indexCursor_.fetch_add(1, std::memory_order_relaxed);
6594514f5e3Sopenharmony_ci    if (cursor >= indexList_.size()) {
6604514f5e3Sopenharmony_ci        return std::nullopt;
6614514f5e3Sopenharmony_ci    }
6624514f5e3Sopenharmony_ci    return indexList_[cursor];
6634514f5e3Sopenharmony_ci}
6644514f5e3Sopenharmony_ci
6654514f5e3Sopenharmony_cistd::unique_ptr<ParallelEvacuator::Workload> ParallelEvacuator::WorkloadSet::TryGetWorkload(size_t index)
6664514f5e3Sopenharmony_ci{
6674514f5e3Sopenharmony_ci    std::unique_ptr<Workload> workload;
6684514f5e3Sopenharmony_ci    if (workloads_.at(index).first.TryAcquire()) {
6694514f5e3Sopenharmony_ci        workload = std::move(workloads_[index].second);
6704514f5e3Sopenharmony_ci    }
6714514f5e3Sopenharmony_ci    return workload;
6724514f5e3Sopenharmony_ci}
6734514f5e3Sopenharmony_ci
6744514f5e3Sopenharmony_civoid ParallelEvacuator::WorkloadSet::Clear()
6754514f5e3Sopenharmony_ci{
6764514f5e3Sopenharmony_ci    workloads_.clear();
6774514f5e3Sopenharmony_ci    indexList_.clear();
6784514f5e3Sopenharmony_ci    indexCursor_.store(0, std::memory_order_relaxed);
6794514f5e3Sopenharmony_ci    remainingWorkloadNum_.store(0, std::memory_order_relaxed);
6804514f5e3Sopenharmony_ci}
6814514f5e3Sopenharmony_ci
6824514f5e3Sopenharmony_ciParallelEvacuator::EvacuationTask::EvacuationTask(int32_t id, uint32_t idOrder, ParallelEvacuator *evacuator)
6834514f5e3Sopenharmony_ci    : Task(id), idOrder_(idOrder), evacuator_(evacuator)
6844514f5e3Sopenharmony_ci{
6854514f5e3Sopenharmony_ci    allocator_ = new TlabAllocator(evacuator->heap_);
6864514f5e3Sopenharmony_ci}
6874514f5e3Sopenharmony_ci
6884514f5e3Sopenharmony_ciParallelEvacuator::EvacuationTask::~EvacuationTask()
6894514f5e3Sopenharmony_ci{
6904514f5e3Sopenharmony_ci    delete allocator_;
6914514f5e3Sopenharmony_ci}
6924514f5e3Sopenharmony_ci
6934514f5e3Sopenharmony_cibool ParallelEvacuator::EvacuationTask::Run(uint32_t threadIndex)
6944514f5e3Sopenharmony_ci{
6954514f5e3Sopenharmony_ci    return evacuator_->EvacuateSpace(allocator_, threadIndex, idOrder_);
6964514f5e3Sopenharmony_ci}
6974514f5e3Sopenharmony_ci
6984514f5e3Sopenharmony_cibool ParallelEvacuator::UpdateReferenceTask::Run([[maybe_unused]] uint32_t threadIndex)
6994514f5e3Sopenharmony_ci{
7004514f5e3Sopenharmony_ci    evacuator_->ProcessWorkloads(false);
7014514f5e3Sopenharmony_ci    return true;
7024514f5e3Sopenharmony_ci}
7034514f5e3Sopenharmony_ci
7044514f5e3Sopenharmony_cibool ParallelEvacuator::EvacuateWorkload::Process([[maybe_unused]] bool isMain)
7054514f5e3Sopenharmony_ci{
7064514f5e3Sopenharmony_ci    return true;
7074514f5e3Sopenharmony_ci}
7084514f5e3Sopenharmony_ci
7094514f5e3Sopenharmony_cibool ParallelEvacuator::UpdateRSetWorkload::Process([[maybe_unused]] bool isMain)
7104514f5e3Sopenharmony_ci{
7114514f5e3Sopenharmony_ci    if (isEdenGC_) {
7124514f5e3Sopenharmony_ci        GetEvacuator()->UpdateRSet<true>(GetRegion());
7134514f5e3Sopenharmony_ci    } else {
7144514f5e3Sopenharmony_ci        GetEvacuator()->UpdateRSet<false>(GetRegion());
7154514f5e3Sopenharmony_ci    }
7164514f5e3Sopenharmony_ci    return true;
7174514f5e3Sopenharmony_ci}
7184514f5e3Sopenharmony_ci
7194514f5e3Sopenharmony_cibool ParallelEvacuator::UpdateNewToEdenRSetWorkload::Process([[maybe_unused]] bool isMain)
7204514f5e3Sopenharmony_ci{
7214514f5e3Sopenharmony_ci    GetEvacuator()->UpdateNewToEdenRSetReference(GetRegion());
7224514f5e3Sopenharmony_ci    return true;
7234514f5e3Sopenharmony_ci}
7244514f5e3Sopenharmony_ci
7254514f5e3Sopenharmony_ci
7264514f5e3Sopenharmony_cibool ParallelEvacuator::UpdateNewRegionWorkload::Process([[maybe_unused]] bool isMain)
7274514f5e3Sopenharmony_ci{
7284514f5e3Sopenharmony_ci    if (isYoungGC_) {
7294514f5e3Sopenharmony_ci        GetEvacuator()->UpdateNewRegionReference<TriggerGCType::YOUNG_GC>(GetRegion());
7304514f5e3Sopenharmony_ci    } else {
7314514f5e3Sopenharmony_ci        GetEvacuator()->UpdateNewRegionReference<TriggerGCType::OLD_GC>(GetRegion());
7324514f5e3Sopenharmony_ci    }
7334514f5e3Sopenharmony_ci    return true;
7344514f5e3Sopenharmony_ci}
7354514f5e3Sopenharmony_ci
7364514f5e3Sopenharmony_cibool ParallelEvacuator::UpdateAndSweepNewRegionWorkload::Process([[maybe_unused]] bool isMain)
7374514f5e3Sopenharmony_ci{
7384514f5e3Sopenharmony_ci    if (isYoungGC_) {
7394514f5e3Sopenharmony_ci        GetEvacuator()->UpdateAndSweepNewRegionReference<TriggerGCType::YOUNG_GC>(GetRegion());
7404514f5e3Sopenharmony_ci    } else {
7414514f5e3Sopenharmony_ci        GetEvacuator()->UpdateAndSweepNewRegionReference<TriggerGCType::OLD_GC>(GetRegion());
7424514f5e3Sopenharmony_ci    }
7434514f5e3Sopenharmony_ci    return true;
7444514f5e3Sopenharmony_ci}
7454514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
746