1/* 2 * Copyright (c) 2021 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/partial_gc.h" 17 18#include "ecmascript/mem/concurrent_marker.h" 19#include "ecmascript/mem/incremental_marker.h" 20#include "ecmascript/mem/parallel_evacuator.h" 21#include "ecmascript/mem/parallel_marker-inl.h" 22#include "ecmascript/runtime_call_id.h" 23#include "ecmascript/mem/verification.h" 24 25namespace panda::ecmascript { 26PartialGC::PartialGC(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {} 27 28void PartialGC::RunPhases() 29{ 30 GCStats *gcStats = heap_->GetEcmaVM()->GetEcmaGCStats(); 31 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PartialGC::RunPhases" + std::to_string(heap_->IsConcurrentFullMark()) 32 + ";Reason" + std::to_string(static_cast<int>(gcStats->GetGCReason())) 33 + ";Sensitive" + std::to_string(static_cast<int>(heap_->GetSensitiveStatus())) 34 + ";IsInBackground" + std::to_string(heap_->IsInBackground()) 35 + ";Startup" + std::to_string(heap_->OnStartupEvent()) 36 + ";ConMark" + std::to_string(static_cast<int>(heap_->GetJSThread()->GetMarkStatus())) 37 + ";Young" + std::to_string(heap_->GetNewSpace()->GetCommittedSize()) 38 + ";Old" + std::to_string(heap_->GetOldSpace()->GetCommittedSize()) 39 + ";TotalCommit" + std::to_string(heap_->GetCommittedSize())); 40 TRACE_GC(GCStats::Scope::ScopeId::TotalGC, gcStats); 41 MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), PartialGC_RunPhases); 42 bool mainThreadInForeground = heap_->GetJSThread()->IsMainThreadFast() && !heap_->IsInBackground(); 43 bool needAjustGCThreadPrio = heap_->GetGCType() == TriggerGCType::OLD_GC || 44 heap_->GetNewSpace()->GetCommittedSize() >= heap_->GetNewSpace()->GetMaximumCapacity(); 45 if (mainThreadInForeground && needAjustGCThreadPrio) { 46 Taskpool::GetCurrentTaskpool()->SetThreadPriority(PriorityMode::STW); 47 } 48 markingInProgress_ = heap_->CheckOngoingConcurrentMarking(); 49 LOG_GC(DEBUG) << "markingInProgress_" << markingInProgress_; 50 Initialize(); 51 Mark(); 52 if (UNLIKELY(heap_->ShouldVerifyHeap())) { 53 Verification::VerifyMark(heap_); 54 } 55 ProcessSharedGCRSetWorkList(); 56 Sweep(); 57 Evacuate(); 58 if (heap_->IsConcurrentFullMark()) { 59 heap_->GetSweeper()->PostTask(); 60 } 61 if (UNLIKELY(heap_->ShouldVerifyHeap())) { 62 Verification::VerifyEvacuate(heap_); 63 } 64 Finish(); 65 if (mainThreadInForeground && needAjustGCThreadPrio) { 66 Taskpool::GetCurrentTaskpool()->SetThreadPriority(PriorityMode::FOREGROUND); 67 } 68} 69 70void PartialGC::Initialize() 71{ 72 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PartialGC::Initialize"); 73 TRACE_GC(GCStats::Scope::ScopeId::Initialize, heap_->GetEcmaVM()->GetEcmaGCStats()); 74 if (!markingInProgress_ && !heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) { 75 LOG_GC(DEBUG) << "No ongoing Concurrent marking. Initializing..."; 76 heap_->Prepare(); 77 if (heap_->IsConcurrentFullMark()) { 78 heap_->GetOldSpace()->SelectCSet(); 79 heap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { 80 current->ClearMarkGCBitset(); 81 current->ClearCrossRegionRSet(); 82 }); 83 heap_->EnumerateNonNewSpaceRegions([](Region *current) { 84 current->ResetAliveObject(); 85 }); 86 } 87 workManager_->Initialize(TriggerGCType::OLD_GC, ParallelGCTaskPhase::OLD_HANDLE_GLOBAL_POOL_TASK); 88 89 freeSize_ = 0; 90 hugeSpaceFreeSize_ = 0; 91 oldSpaceCommitSize_ = heap_->GetOldSpace()->GetCommittedSize(); 92 nonMoveSpaceCommitSize_ = heap_->GetNonMovableSpace()->GetCommittedSize(); 93 } 94} 95 96void PartialGC::Finish() 97{ 98 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PartialGC::Finish"); 99 TRACE_GC(GCStats::Scope::ScopeId::Finish, heap_->GetEcmaVM()->GetEcmaGCStats()); 100 heap_->Resume(OLD_GC); 101 if (heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) { 102 heap_->GetIncrementalMarker()->Reset(); 103 } else if (markingInProgress_) { 104 auto marker = heap_->GetConcurrentMarker(); 105 marker->Reset(false); 106 } else { 107 workManager_->Finish(); 108 } 109 if (heap_->IsConcurrentFullMark()) { 110 heap_->GetSweeper()->TryFillSweptRegion(); 111 heap_->SetFullMarkRequestedState(false); 112 } 113} 114 115void PartialGC::Mark() 116{ 117 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PartialGC::Mark"); 118 TRACE_GC(GCStats::Scope::ScopeId::Mark, heap_->GetEcmaVM()->GetEcmaGCStats()); 119 if (markingInProgress_) { 120 heap_->GetConcurrentMarker()->ReMark(); 121 return; 122 } 123 heap_->GetNonMovableMarker()->MarkRoots(MAIN_THREAD_INDEX); 124 if (heap_->IsConcurrentFullMark()) { 125 heap_->GetNonMovableMarker()->ProcessMarkStack(MAIN_THREAD_INDEX); 126 } else if (heap_->IsEdenMark()) { 127 { 128 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::ProcessOldToNew"); 129 heap_->GetNonMovableMarker()->ProcessOldToNew(MAIN_THREAD_INDEX); 130 } 131 { 132 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::ProcessNewToEden"); 133 heap_->GetNonMovableMarker()->ProcessNewToEden(MAIN_THREAD_INDEX); 134 } 135 heap_->GetNonMovableMarker()->ProcessSnapshotRSet(MAIN_THREAD_INDEX); 136 } else if (heap_->IsYoungMark()) { 137 { 138 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::ProcessOldToNew"); 139 heap_->GetNonMovableMarker()->ProcessOldToNew(MAIN_THREAD_INDEX); 140 } 141 heap_->GetNonMovableMarker()->ProcessSnapshotRSet(MAIN_THREAD_INDEX); 142 } 143 heap_->WaitRunningTaskFinished(); 144 // MarkJitCodeMap must be call after other mark work finish to make sure which jserror object js alive. 145 heap_->GetNonMovableMarker()->MarkJitCodeMap(MAIN_THREAD_INDEX); 146} 147 148void PartialGC::Sweep() 149{ 150 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PartialGC::Sweep"); 151 ProcessNativeDelete(); 152 if (heap_->IsConcurrentFullMark()) { 153 heap_->GetOldSpace()->EnumerateRegions([](Region *current) { 154 current->SetRegionAliveSize(); 155 }); 156 TRACE_GC(GCStats::Scope::ScopeId::Sweep, heap_->GetEcmaVM()->GetEcmaGCStats()); 157 heap_->GetSweeper()->Sweep(); 158 } 159} 160 161void PartialGC::ProcessNativeDelete() 162{ 163 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::ProcessNativeDelete"); 164 TRACE_GC(GCStats::Scope::ScopeId::ClearNativeObject, heap_->GetEcmaVM()->GetEcmaGCStats()); 165 WeakRootVisitor gcUpdateWeak = [this](TaggedObject *header) -> TaggedObject* { 166 Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(header)); 167 ASSERT(!objectRegion->InSharedHeap()); 168 if (heap_->IsEdenMark() && !objectRegion->InEdenSpace()) { 169 return header; 170 } 171 if (!objectRegion->InGeneralNewSpaceOrCSet() && heap_->IsYoungMark()) { 172 return header; 173 } 174 if (!objectRegion->Test(header)) { 175 return nullptr; 176 } 177 return header; 178 }; 179 heap_->GetEcmaVM()->ProcessNativeDelete(gcUpdateWeak); 180} 181 182void PartialGC::Evacuate() 183{ 184 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PartialGC::Evacuate"); 185 TRACE_GC(GCStats::Scope::ScopeId::Evacuate, heap_->GetEcmaVM()->GetEcmaGCStats()); 186 heap_->GetEvacuator()->Evacuate(); 187} 188 189ARK_INLINE void PartialGC::ProcessSharedGCRSetWorkList() 190{ 191 TRACE_GC(GCStats::Scope::ScopeId::ProcessSharedGCRSetWorkList, heap_->GetEcmaVM()->GetEcmaGCStats()); 192 heap_->ProcessSharedGCRSetWorkList(); 193} 194} // namespace panda::ecmascript 195