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 
25 namespace panda::ecmascript {
PartialGC(Heap *heap)26 PartialGC::PartialGC(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {}
27 
RunPhases()28 void 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 
Initialize()70 void 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 
Finish()96 void 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 
Mark()115 void 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 
Sweep()148 void 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 
ProcessNativeDelete()161 void 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 
Evacuate()182 void 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 
ProcessSharedGCRSetWorkList()189 ARK_INLINE void PartialGC::ProcessSharedGCRSetWorkList()
190 {
191     TRACE_GC(GCStats::Scope::ScopeId::ProcessSharedGCRSetWorkList, heap_->GetEcmaVM()->GetEcmaGCStats());
192     heap_->ProcessSharedGCRSetWorkList();
193 }
194 }  // namespace panda::ecmascript
195