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