1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/mem/shared_heap/shared_gc.h" 17 18#include "ecmascript/mem/shared_heap/shared_concurrent_marker.h" 19#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h" 20#include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h" 21#include "ecmascript/mem/verification.h" 22#include "ecmascript/runtime.h" 23 24namespace panda::ecmascript { 25void SharedGC::RunPhases() 26{ 27 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::RunPhases" 28 + std::to_string(static_cast<int>(sHeap_->GetEcmaGCStats()->GetGCReason())) 29 + ";Sensitive" + std::to_string(static_cast<int>(sHeap_->GetSensitiveStatus())) 30 + ";IsInBackground" + std::to_string(sHeap_->IsInBackground()) 31 + ";Startup" + std::to_string(sHeap_->OnStartupEvent()) 32 + ";Old" + std::to_string(sHeap_->GetOldSpace()->GetCommittedSize()) 33 + ";huge" + std::to_string(sHeap_->GetHugeObjectSpace()->GetCommittedSize()) 34 + ";NonMov" + std::to_string(sHeap_->GetNonMovableSpace()->GetCommittedSize()) 35 + ";TotCommit" + std::to_string(sHeap_->GetCommittedSize())); 36 TRACE_GC(GCStats::Scope::ScopeId::TotalGC, sHeap_->GetEcmaGCStats()); 37 markingInProgress_ = sHeap_->CheckOngoingConcurrentMarking(); 38 Initialize(); 39 Mark(); 40 if (UNLIKELY(sHeap_->ShouldVerifyHeap())) { 41 // verify mark 42 LOG_ECMA(DEBUG) << "start verify mark"; 43 SharedHeapVerification(sHeap_, VerifyKind::VERIFY_SHARED_GC_MARK).VerifyMark(markingInProgress_); 44 } 45 Sweep(); 46 if (UNLIKELY(sHeap_->ShouldVerifyHeap())) { 47 // verify sweep 48 LOG_ECMA(DEBUG) << "start verify sweep"; 49 SharedHeapVerification(sHeap_, VerifyKind::VERIFY_SHARED_GC_SWEEP).VerifySweep(markingInProgress_); 50 } 51 Finish(); 52 sHeap_->ResetNativeSizeAfterLastGC(); 53} 54 55void SharedGC::Initialize() 56{ 57 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Initialize"); 58 TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats()); 59 if (!markingInProgress_) { 60 sHeap_->Prepare(true); 61 sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { 62 current->ClearMarkGCBitset(); 63 }); 64 sHeap_->EnumerateOldSpaceRegions([](Region *current) { 65 ASSERT(current->InSharedSweepableSpace()); 66 current->ResetAliveObject(); 67 }); 68 sWorkManager_->Initialize(TriggerGCType::SHARED_GC, SharedParallelMarkPhase::SHARED_MARK_TASK); 69 } 70} 71void SharedGC::Mark() 72{ 73 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Mark"); 74 TRACE_GC(GCStats::Scope::ScopeId::Mark, sHeap_->GetEcmaGCStats()); 75 if (markingInProgress_) { 76 sHeap_->GetConcurrentMarker()->ReMark(); 77 return; 78 } 79 SharedGCMarker *marker = sHeap_->GetSharedGCMarker(); 80 marker->MarkRoots(DAEMON_THREAD_INDEX, SharedMarkType::NOT_CONCURRENT_MARK); 81 marker->DoMark<SharedMarkType::NOT_CONCURRENT_MARK>(DAEMON_THREAD_INDEX); 82 marker->MergeBackAndResetRSetWorkListHandler(); 83 sHeap_->WaitRunningTaskFinished(); 84} 85 86void SharedGC::Sweep() 87{ 88 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Sweep"); 89 TRACE_GC(GCStats::Scope::ScopeId::Sweep, sHeap_->GetEcmaGCStats()); 90 UpdateRecordWeakReference(); 91 WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) -> TaggedObject* { 92 Region *objectRegion = Region::ObjectAddressToRange(header); 93 if (UNLIKELY(objectRegion == nullptr)) { 94 LOG_GC(ERROR) << "SharedGC updateWeakReference: region is nullptr, header is " << header; 95 return nullptr; 96 } 97 if (!objectRegion->InSharedSweepableSpace() || objectRegion->Test(header)) { 98 return header; 99 } 100 return nullptr; 101 }; 102 auto stringTableCleaner = Runtime::GetInstance()->GetEcmaStringTable()->GetCleaner(); 103 stringTableCleaner->PostSweepWeakRefTask(gcUpdateWeak); 104 Runtime::GetInstance()->ProcessNativeDeleteInSharedGC(gcUpdateWeak); 105 Runtime::GetInstance()->ProcessSharedNativeDelete(gcUpdateWeak); 106 107 Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) { 108 ASSERT(!thread->IsInRunningState()); 109 thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, GCKind::SHARED_GC); 110 const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->ResetTlab(); 111 }); 112 113 stringTableCleaner->JoinAndWaitSweepWeakRefTask(gcUpdateWeak); 114 sHeap_->GetSweeper()->Sweep(false); 115 sHeap_->GetSweeper()->PostTask(false); 116} 117 118void SharedGC::Finish() 119{ 120 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Finish"); 121 TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats()); 122 sHeap_->Reclaim(TriggerGCType::SHARED_GC); 123 if (markingInProgress_) { 124 sHeap_->GetConcurrentMarker()->Reset(false); 125 } else { 126 sWorkManager_->Finish(); 127 } 128 sHeap_->GetSweeper()->TryFillSweptRegion(); 129} 130 131void SharedGC::UpdateRecordWeakReference() 132{ 133 auto totalThreadCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1; 134 for (uint32_t i = 0; i < totalThreadCount; i++) { 135 ProcessQueue *queue = sHeap_->GetWorkManager()->GetWeakReferenceQueue(i); 136 137 while (true) { 138 auto obj = queue->PopBack(); 139 if (UNLIKELY(obj == nullptr)) { 140 break; 141 } 142 ObjectSlot slot(ToUintPtr(obj)); 143 JSTaggedValue value(slot.GetTaggedType()); 144 if (value.IsWeak()) { 145 auto header = value.GetTaggedWeakRef(); 146 Region *objectRegion = Region::ObjectAddressToRange(header); 147 if (!objectRegion->Test(header)) { 148 slot.Clear(); 149 } 150 } 151 } 152 } 153} 154 155void SharedGC::ResetWorkManager(SharedGCWorkManager *sWorkManager) 156{ 157 sWorkManager_ = sWorkManager; 158} 159} // namespace panda::ecmascript 160