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> ®ion) { 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, ®ion, &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> ®ion) { 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