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#include "ecmascript/mem/concurrent_marker.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/mem/parallel_marker-inl.h" 194514f5e3Sopenharmony_ci#include "ecmascript/runtime_call_id.h" 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_cinamespace panda::ecmascript { 224514f5e3Sopenharmony_cisize_t ConcurrentMarker::taskCounts_ = 0; 234514f5e3Sopenharmony_ciMutex ConcurrentMarker::taskCountMutex_; 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_ciConcurrentMarker::ConcurrentMarker(Heap *heap, EnableConcurrentMarkType type) 264514f5e3Sopenharmony_ci : heap_(heap), 274514f5e3Sopenharmony_ci vm_(heap->GetEcmaVM()), 284514f5e3Sopenharmony_ci thread_(vm_->GetJSThread()), 294514f5e3Sopenharmony_ci workManager_(heap->GetWorkManager()), 304514f5e3Sopenharmony_ci enableMarkType_(type) 314514f5e3Sopenharmony_ci{ 324514f5e3Sopenharmony_ci thread_->SetMarkStatus(MarkStatus::READY_TO_MARK); 334514f5e3Sopenharmony_ci} 344514f5e3Sopenharmony_ci 354514f5e3Sopenharmony_civoid ConcurrentMarker::EnableConcurrentMarking(EnableConcurrentMarkType type) 364514f5e3Sopenharmony_ci{ 374514f5e3Sopenharmony_ci if (IsConfigDisabled()) { 384514f5e3Sopenharmony_ci return; 394514f5e3Sopenharmony_ci } 404514f5e3Sopenharmony_ci if (IsEnabled() && !thread_->IsReadyToConcurrentMark() && type == EnableConcurrentMarkType::DISABLE) { 414514f5e3Sopenharmony_ci enableMarkType_ = EnableConcurrentMarkType::REQUEST_DISABLE; 424514f5e3Sopenharmony_ci } else { 434514f5e3Sopenharmony_ci enableMarkType_ = type; 444514f5e3Sopenharmony_ci } 454514f5e3Sopenharmony_ci} 464514f5e3Sopenharmony_ci 474514f5e3Sopenharmony_civoid ConcurrentMarker::Mark() 484514f5e3Sopenharmony_ci{ 494514f5e3Sopenharmony_ci RecursionScope recurScope(this); 504514f5e3Sopenharmony_ci TRACE_GC(GCStats::Scope::ScopeId::ConcurrentMark, heap_->GetEcmaVM()->GetEcmaGCStats()); 514514f5e3Sopenharmony_ci LOG_GC(DEBUG) << "ConcurrentMarker: Concurrent Marking Begin"; 524514f5e3Sopenharmony_ci ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "ConcurrentMarker::Mark"); 534514f5e3Sopenharmony_ci MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarking); 544514f5e3Sopenharmony_ci InitializeMarking(); 554514f5e3Sopenharmony_ci clockScope_.Reset(); 564514f5e3Sopenharmony_ci heap_->PostParallelGCTask(ParallelGCTaskPhase::CONCURRENT_HANDLE_GLOBAL_POOL_TASK); 574514f5e3Sopenharmony_ci} 584514f5e3Sopenharmony_ci 594514f5e3Sopenharmony_civoid ConcurrentMarker::Finish() 604514f5e3Sopenharmony_ci{ 614514f5e3Sopenharmony_ci workManager_->Finish(); 624514f5e3Sopenharmony_ci} 634514f5e3Sopenharmony_ci 644514f5e3Sopenharmony_civoid ConcurrentMarker::ReMark() 654514f5e3Sopenharmony_ci{ 664514f5e3Sopenharmony_ci TRACE_GC(GCStats::Scope::ScopeId::ReMark, heap_->GetEcmaVM()->GetEcmaGCStats()); 674514f5e3Sopenharmony_ci LOG_GC(DEBUG) << "ConcurrentMarker: Remarking Begin"; 684514f5e3Sopenharmony_ci MEM_ALLOCATE_AND_GC_TRACE(vm_, ReMarking); 694514f5e3Sopenharmony_ci Marker *nonMovableMarker = heap_->GetNonMovableMarker(); 704514f5e3Sopenharmony_ci nonMovableMarker->MarkRoots(MAIN_THREAD_INDEX); 714514f5e3Sopenharmony_ci nonMovableMarker->ProcessMarkStack(MAIN_THREAD_INDEX); 724514f5e3Sopenharmony_ci heap_->WaitRunningTaskFinished(); 734514f5e3Sopenharmony_ci // MarkJitCodeMap must be call after other mark work finish to make sure which jserror object js alive. 744514f5e3Sopenharmony_ci nonMovableMarker->MarkJitCodeMap(MAIN_THREAD_INDEX); 754514f5e3Sopenharmony_ci} 764514f5e3Sopenharmony_ci 774514f5e3Sopenharmony_civoid ConcurrentMarker::HandleMarkingFinished(GCReason gcReason) // js-thread wait for sweep 784514f5e3Sopenharmony_ci{ 794514f5e3Sopenharmony_ci LockHolder lock(waitMarkingFinishedMutex_); 804514f5e3Sopenharmony_ci ASSERT(markingFinished_); 814514f5e3Sopenharmony_ci TriggerGCType gcType; 824514f5e3Sopenharmony_ci if (heap_->IsConcurrentFullMark()) { 834514f5e3Sopenharmony_ci gcType = TriggerGCType::OLD_GC; 844514f5e3Sopenharmony_ci } else if (heap_->IsEdenMark()) { 854514f5e3Sopenharmony_ci gcType = TriggerGCType::EDEN_GC; 864514f5e3Sopenharmony_ci } else { 874514f5e3Sopenharmony_ci gcType = TriggerGCType::YOUNG_GC; 884514f5e3Sopenharmony_ci } 894514f5e3Sopenharmony_ci heap_->CollectGarbage(gcType, gcReason); 904514f5e3Sopenharmony_ci} 914514f5e3Sopenharmony_ci 924514f5e3Sopenharmony_civoid ConcurrentMarker::WaitMarkingFinished() // call in EcmaVm thread, wait for mark finished 934514f5e3Sopenharmony_ci{ 944514f5e3Sopenharmony_ci LockHolder lock(waitMarkingFinishedMutex_); 954514f5e3Sopenharmony_ci while (!markingFinished_) { 964514f5e3Sopenharmony_ci waitMarkingFinishedCV_.Wait(&waitMarkingFinishedMutex_); 974514f5e3Sopenharmony_ci } 984514f5e3Sopenharmony_ci} 994514f5e3Sopenharmony_ci 1004514f5e3Sopenharmony_civoid ConcurrentMarker::Reset(bool revertCSet) 1014514f5e3Sopenharmony_ci{ 1024514f5e3Sopenharmony_ci ASSERT(runningTaskCount_ == 0); 1034514f5e3Sopenharmony_ci Finish(); 1044514f5e3Sopenharmony_ci thread_->SetMarkStatus(MarkStatus::READY_TO_MARK); 1054514f5e3Sopenharmony_ci isConcurrentMarking_ = false; 1064514f5e3Sopenharmony_ci markingFinished_ = false; 1074514f5e3Sopenharmony_ci notifyMarkingFinished_ = false; 1084514f5e3Sopenharmony_ci if (revertCSet) { 1094514f5e3Sopenharmony_ci // Partial gc clear cset when evacuation allocator finalize 1104514f5e3Sopenharmony_ci heap_->GetOldSpace()->RevertCSet(); 1114514f5e3Sopenharmony_ci auto callback = [](Region *region) { 1124514f5e3Sopenharmony_ci region->ResetRegionTypeFlag(); 1134514f5e3Sopenharmony_ci region->ClearMarkGCBitset(); 1144514f5e3Sopenharmony_ci region->ClearCrossRegionRSet(); 1154514f5e3Sopenharmony_ci region->ResetAliveObject(); 1164514f5e3Sopenharmony_ci }; 1174514f5e3Sopenharmony_ci if (heap_->IsConcurrentFullMark()) { 1184514f5e3Sopenharmony_ci heap_->EnumerateRegions(callback); 1194514f5e3Sopenharmony_ci } else { 1204514f5e3Sopenharmony_ci heap_->EnumerateNewSpaceRegions(callback); 1214514f5e3Sopenharmony_ci } 1224514f5e3Sopenharmony_ci } 1234514f5e3Sopenharmony_ci} 1244514f5e3Sopenharmony_ci 1254514f5e3Sopenharmony_civoid ConcurrentMarker::InitializeMarking() 1264514f5e3Sopenharmony_ci{ 1274514f5e3Sopenharmony_ci ASSERT(runningTaskCount_ == 0); 1284514f5e3Sopenharmony_ci MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarkingInitialize); 1294514f5e3Sopenharmony_ci heap_->Prepare(); 1304514f5e3Sopenharmony_ci ASSERT(VerifyAllRegionsNonFresh()); 1314514f5e3Sopenharmony_ci heap_->GetNewSpace()->RecordCurrentRegionAsHalfFresh(); 1324514f5e3Sopenharmony_ci isConcurrentMarking_ = true; 1334514f5e3Sopenharmony_ci thread_->SetMarkStatus(MarkStatus::MARKING); 1344514f5e3Sopenharmony_ci 1354514f5e3Sopenharmony_ci if (heap_->IsConcurrentFullMark()) { 1364514f5e3Sopenharmony_ci heapObjectSize_ = heap_->GetHeapObjectSize(); 1374514f5e3Sopenharmony_ci heap_->GetOldSpace()->SelectCSet(); 1384514f5e3Sopenharmony_ci heap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { 1394514f5e3Sopenharmony_ci current->ClearMarkGCBitset(); 1404514f5e3Sopenharmony_ci current->ClearCrossRegionRSet(); 1414514f5e3Sopenharmony_ci }); 1424514f5e3Sopenharmony_ci // The alive object size of Region in OldSpace will be recalculated. 1434514f5e3Sopenharmony_ci heap_->EnumerateNonNewSpaceRegions([](Region *current) { 1444514f5e3Sopenharmony_ci current->ResetAliveObject(); 1454514f5e3Sopenharmony_ci }); 1464514f5e3Sopenharmony_ci } else if (heap_->IsEdenMark()) { 1474514f5e3Sopenharmony_ci heapObjectSize_ = heap_->GetEdenSpace()->GetHeapObjectSize(); 1484514f5e3Sopenharmony_ci } else { 1494514f5e3Sopenharmony_ci heapObjectSize_ = heap_->GetNewSpace()->GetHeapObjectSize(); 1504514f5e3Sopenharmony_ci } 1514514f5e3Sopenharmony_ci workManager_->Initialize(TriggerGCType::OLD_GC, ParallelGCTaskPhase::CONCURRENT_HANDLE_GLOBAL_POOL_TASK); 1524514f5e3Sopenharmony_ci if (heap_->IsYoungMark()) { 1534514f5e3Sopenharmony_ci { 1544514f5e3Sopenharmony_ci ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkOldToNew"); 1554514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->ProcessOldToNewNoMarkStack(MAIN_THREAD_INDEX); 1564514f5e3Sopenharmony_ci } 1574514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->ProcessSnapshotRSetNoMarkStack(MAIN_THREAD_INDEX); 1584514f5e3Sopenharmony_ci } else if (heap_->IsEdenMark()) { 1594514f5e3Sopenharmony_ci { 1604514f5e3Sopenharmony_ci ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkNewToEden"); 1614514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->ProcessOldToNewNoMarkStack(MAIN_THREAD_INDEX); 1624514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->ProcessNewToEdenNoMarkStack(MAIN_THREAD_INDEX); 1634514f5e3Sopenharmony_ci } 1644514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->ProcessSnapshotRSetNoMarkStack(MAIN_THREAD_INDEX); 1654514f5e3Sopenharmony_ci } 1664514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->MarkRoots(MAIN_THREAD_INDEX); 1674514f5e3Sopenharmony_ci} 1684514f5e3Sopenharmony_ci 1694514f5e3Sopenharmony_cibool ConcurrentMarker::ShouldNotifyMarkingFinished() 1704514f5e3Sopenharmony_ci{ 1714514f5e3Sopenharmony_ci if (runningTaskCount_.fetch_sub(1, std::memory_order_relaxed) != 1) { 1724514f5e3Sopenharmony_ci return false; 1734514f5e3Sopenharmony_ci } 1744514f5e3Sopenharmony_ci return reinterpret_cast<std::atomic<bool>*>(¬ifyMarkingFinished_) 1754514f5e3Sopenharmony_ci ->exchange(true, std::memory_order_relaxed) == false; 1764514f5e3Sopenharmony_ci} 1774514f5e3Sopenharmony_ci 1784514f5e3Sopenharmony_civoid ConcurrentMarker::FinishMarking() 1794514f5e3Sopenharmony_ci{ 1804514f5e3Sopenharmony_ci LockHolder lock(waitMarkingFinishedMutex_); 1814514f5e3Sopenharmony_ci ASSERT(!markingFinished_); 1824514f5e3Sopenharmony_ci ASSERT(notifyMarkingFinished_); 1834514f5e3Sopenharmony_ci float spendTime = clockScope_.TotalSpentTime(); 1844514f5e3Sopenharmony_ci if (heap_->IsYoungMark()) { 1854514f5e3Sopenharmony_ci heapObjectSize_ = heap_->GetNewSpace()->GetHeapObjectSize(); 1864514f5e3Sopenharmony_ci } else if (heap_->IsConcurrentFullMark()) { 1874514f5e3Sopenharmony_ci heapObjectSize_ = heap_->GetHeapObjectSize(); 1884514f5e3Sopenharmony_ci } else if (heap_->IsEdenMark()) { 1894514f5e3Sopenharmony_ci heapObjectSize_ = heap_->GetEdenSpace()->GetHeapObjectSize(); 1904514f5e3Sopenharmony_ci } 1914514f5e3Sopenharmony_ci SetDuration(spendTime); 1924514f5e3Sopenharmony_ci if (heap_->IsFullMarkRequested()) { 1934514f5e3Sopenharmony_ci heap_->SetFullMarkRequestedState(false); 1944514f5e3Sopenharmony_ci } 1954514f5e3Sopenharmony_ci thread_->SetMarkStatus(MarkStatus::MARK_FINISHED); 1964514f5e3Sopenharmony_ci thread_->SetCheckSafePointStatus(); 1974514f5e3Sopenharmony_ci markingFinished_ = true; 1984514f5e3Sopenharmony_ci waitMarkingFinishedCV_.Signal(); 1994514f5e3Sopenharmony_ci DecreaseTaskCounts(); 2004514f5e3Sopenharmony_ci} 2014514f5e3Sopenharmony_ci 2024514f5e3Sopenharmony_civoid ConcurrentMarker::ProcessConcurrentMarkTask(uint32_t threadId) 2034514f5e3Sopenharmony_ci{ 2044514f5e3Sopenharmony_ci runningTaskCount_.fetch_add(1, std::memory_order_relaxed); 2054514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->ProcessMarkStack(threadId); 2064514f5e3Sopenharmony_ci if (ShouldNotifyMarkingFinished()) { 2074514f5e3Sopenharmony_ci FinishMarking(); 2084514f5e3Sopenharmony_ci heap_->GetIdleGCTrigger()->TryPostHandleMarkFinished(); 2094514f5e3Sopenharmony_ci } 2104514f5e3Sopenharmony_ci} 2114514f5e3Sopenharmony_ci 2124514f5e3Sopenharmony_cibool ConcurrentMarker::VerifyAllRegionsNonFresh() 2134514f5e3Sopenharmony_ci{ 2144514f5e3Sopenharmony_ci bool ok = true; 2154514f5e3Sopenharmony_ci heap_->EnumerateRegions([&ok](Region *region) { 2164514f5e3Sopenharmony_ci ok &= !region->IsFreshRegion() && !region->IsHalfFreshRegion(); 2174514f5e3Sopenharmony_ci }); 2184514f5e3Sopenharmony_ci return ok; 2194514f5e3Sopenharmony_ci} 2204514f5e3Sopenharmony_ci} // namespace panda::ecmascript 221