1 /**
2 * Copyright (c) 2021-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 "runtime/mem/gc/stw-gc/stw-gc.h"
17
18 #include "libpandabase/trace/trace.h"
19 #include "libpandabase/utils/logger.h"
20 #include "runtime/include/object_header-inl.h"
21 #include "runtime/include/panda_vm.h"
22 #include "runtime/mem/gc/gc_root-inl.h"
23 #include "runtime/mem/gc/workers/gc_workers_task_pool.h"
24 #include "runtime/mem/object_helpers.h"
25 #include "runtime/mem/pygote_space_allocator-inl.h"
26 #include "runtime/mem/gc/static/gc_marker_static-inl.h"
27 #include "runtime/mem/gc/dynamic/gc_marker_dynamic-inl.h"
28 #include "runtime/mem/gc/gc_adaptive_stack_inl.h"
29
30 namespace ark::mem {
31
32 template <class LanguageConfig>
StwGC(ObjectAllocatorBase * objectAllocator,const GCSettings & settings)33 StwGC<LanguageConfig>::StwGC(ObjectAllocatorBase *objectAllocator, const GCSettings &settings)
34 : GCLang<LanguageConfig>(objectAllocator, settings), marker_(this)
35 {
36 this->SetType(GCType::STW_GC);
37 }
38
39 template <class LanguageConfig>
InitializeImpl()40 void StwGC<LanguageConfig>::InitializeImpl()
41 {
42 trace::ScopedTrace scopedTrace(__FUNCTION__);
43 InternalAllocatorPtr allocator = this->GetInternalAllocator();
44 auto barrierSet = allocator->New<GCDummyBarrierSet>(allocator);
45 ASSERT(barrierSet != nullptr);
46 this->SetGCBarrierSet(barrierSet);
47 this->CreateWorkersTaskPool();
48 LOG_DEBUG_GC << "STW GC Initialized";
49 }
50
51 template <class LanguageConfig>
CheckGCCause(GCTaskCause cause) const52 bool StwGC<LanguageConfig>::CheckGCCause(GCTaskCause cause) const
53 {
54 // Causes for generational GC are unsuitable for STW (non-generational) GC
55 if (cause == GCTaskCause::YOUNG_GC_CAUSE || cause == GCTaskCause::MIXED) {
56 return false;
57 }
58 return cause != GCTaskCause::CROSSREF_CAUSE && cause != GCTaskCause::INVALID_CAUSE;
59 }
60
61 template <class LanguageConfig>
RunPhasesImpl(GCTask & task)62 void StwGC<LanguageConfig>::RunPhasesImpl(GCTask &task)
63 {
64 trace::ScopedTrace scopedTrace(__FUNCTION__);
65 auto memStats = this->GetPandaVm()->GetMemStats();
66 GCScopedPauseStats scopedPauseStats(this->GetPandaVm()->GetGCStats(), this->GetStats());
67 [[maybe_unused]] size_t bytesInHeapBeforeGc = memStats->GetFootprintHeap();
68 marker_.BindBitmaps(true);
69 Mark(task);
70 Sweep();
71 marker_.ReverseMark();
72 [[maybe_unused]] size_t bytesInHeapAfterGc = memStats->GetFootprintHeap();
73 ASSERT(bytesInHeapAfterGc <= bytesInHeapBeforeGc);
74 task.collectionType = GCCollectionType::FULL;
75 }
76
77 template <class LanguageConfig>
Mark(const GCTask & task)78 void StwGC<LanguageConfig>::Mark(const GCTask &task)
79 {
80 GCScope<TRACE_PHASE> gcScope(__FUNCTION__, this, GCPhase::GC_PHASE_MARK);
81
82 // Iterate over roots and add other roots
83 bool useGcWorkers = this->GetSettings()->ParallelMarkingEnabled();
84 GCMarkingStackType objectsStack(this, useGcWorkers ? this->GetSettings()->GCRootMarkingStackMaxSize() : 0,
85 useGcWorkers ? this->GetSettings()->GCWorkersMarkingStackMaxSize() : 0,
86 GCWorkersTaskTypes::TASK_MARKING,
87 this->GetSettings()->GCMarkingStackNewTasksFrequency());
88
89 this->VisitRoots(
90 [&objectsStack, &useGcWorkers, this](const GCRoot &gcRoot) {
91 LOG_DEBUG_GC << "Handle root " << GetDebugInfoAboutObject(gcRoot.GetObjectHeader());
92 if (marker_.MarkIfNotMarked(gcRoot.GetObjectHeader())) {
93 objectsStack.PushToStack(gcRoot.GetType(), gcRoot.GetObjectHeader());
94 }
95 if (!useGcWorkers) {
96 MarkStack(&objectsStack);
97 }
98 },
99 VisitGCRootFlags::ACCESS_ROOT_ALL);
100
101 this->GetPandaVm()->VisitStringTable(
102 [this, &objectsStack](ObjectHeader *str) {
103 if (this->marker_.MarkIfNotMarked(str)) {
104 ASSERT(str != nullptr);
105 objectsStack.PushToStack(RootType::STRING_TABLE, str);
106 }
107 },
108 VisitGCRootFlags::ACCESS_ROOT_ALL);
109 MarkStack(&objectsStack);
110 ASSERT(objectsStack.Empty());
111 if (useGcWorkers) {
112 this->GetWorkersTaskPool()->WaitUntilTasksEnd();
113 }
114 auto refClearPred = [this]([[maybe_unused]] const ObjectHeader *obj) { return this->InGCSweepRange(obj); };
115 // NOLINTNEXTLINE(performance-unnecessary-value-param)
116 this->GetPandaVm()->HandleReferences(task, refClearPred);
117 }
118
119 template <class LanguageConfig>
MarkStack(GCMarkingStackType * stack)120 void StwGC<LanguageConfig>::MarkStack(GCMarkingStackType *stack)
121 {
122 trace::ScopedTrace scopedTrace(__FUNCTION__);
123 ASSERT(stack != nullptr);
124 size_t objectsCount = 0;
125 auto refPred = [this](const ObjectHeader *obj) { return this->InGCSweepRange(obj); };
126 while (!stack->Empty()) {
127 objectsCount++;
128 auto *object = this->PopObjectFromStack(stack);
129 ValidateObject(nullptr, object);
130 auto *baseClass = object->template ClassAddr<BaseClass>();
131 LOG_DEBUG_GC << "Current object: " << GetDebugInfoAboutObject(object);
132 this->marker_.MarkInstance(stack, object, baseClass, refPred);
133 }
134 LOG_DEBUG_GC << "Iterated over " << objectsCount << " objects in the stack";
135 }
136
137 template <class LanguageConfig>
Sweep()138 void StwGC<LanguageConfig>::Sweep()
139 {
140 GCScope<TRACE_PHASE> gcScope(__FUNCTION__, this, GCPhase::GC_PHASE_SWEEP);
141 if (!marker_.IsReverseMark()) {
142 LOG_DEBUG_GC << "Sweep with MarkChecker";
143 SweepImpl<DIRECT_MARK>();
144 } else {
145 LOG_DEBUG_GC << "Sweep with ReverseMarkChecker";
146 SweepImpl<REVERSE_MARK>();
147 }
148 }
149
150 template <class LanguageConfig>
151 template <typename StwGC<LanguageConfig>::MarkType MARK_TYPE>
SweepImpl()152 void StwGC<LanguageConfig>::SweepImpl()
153 {
154 this->GetPandaVm()->SweepVmRefs([this](ObjectHeader *object) {
155 return this->marker_.template MarkChecker<static_cast<bool>(MARK_TYPE)>(object);
156 });
157 this->GetObjectAllocator()->Collect(
158 [this](ObjectHeader *object) {
159 auto status = this->marker_.template MarkChecker<static_cast<bool>(MARK_TYPE)>(object);
160 if (status == ObjectStatus::DEAD_OBJECT) {
161 LOG_DEBUG_OBJECT_EVENTS << "DELETE OBJECT: " << object;
162 }
163 return status;
164 },
165 GCCollectMode::GC_ALL);
166 this->GetObjectAllocator()->VisitAndRemoveFreePools(
167 [](void *mem, [[maybe_unused]] size_t size) { PoolManager::GetMmapMemPool()->FreePool(mem, size); });
168 }
169
170 template <class LanguageConfig>
InitGCBits(ark::ObjectHeader * object)171 void StwGC<LanguageConfig>::InitGCBits(ark::ObjectHeader *object)
172 {
173 if (!marker_.IsReverseMark()) {
174 object->SetUnMarkedForGC();
175 ASSERT(!object->IsMarkedForGC());
176 } else {
177 object->SetMarkedForGC();
178 ASSERT(object->IsMarkedForGC());
179 }
180 LOG_DEBUG_GC << "Init gc bits for object: " << std::hex << object << " bit: " << object->IsMarkedForGC()
181 << " reversed_mark: " << marker_.IsReverseMark();
182 }
183
184 template <class LanguageConfig>
InitGCBitsForAllocationInTLAB(ark::ObjectHeader * objHeader)185 void StwGC<LanguageConfig>::InitGCBitsForAllocationInTLAB([[maybe_unused]] ark::ObjectHeader *objHeader)
186 {
187 LOG(FATAL, GC) << "TLABs are not supported by this GC";
188 }
189
190 template <class LanguageConfig>
Trigger(PandaUniquePtr<GCTask> task)191 bool StwGC<LanguageConfig>::Trigger(PandaUniquePtr<GCTask> task)
192 {
193 return this->AddGCTask(true, std::move(task));
194 }
195
196 template <class LanguageConfig>
WorkerTaskProcessing(GCWorkersTask * task,void * workerData)197 void StwGC<LanguageConfig>::WorkerTaskProcessing(GCWorkersTask *task, [[maybe_unused]] void *workerData)
198 {
199 switch (task->GetType()) {
200 case GCWorkersTaskTypes::TASK_MARKING: {
201 auto *stack = task->Cast<GCMarkWorkersTask>()->GetMarkingStack();
202 MarkStack(stack);
203 this->GetInternalAllocator()->Delete(stack);
204 break;
205 }
206 default:
207 LOG(FATAL, GC) << "Unimplemented for " << GCWorkersTaskTypesToString(task->GetType());
208 UNREACHABLE();
209 }
210 }
211
212 template <class LanguageConfig>
IsPostponeGCSupported() const213 bool StwGC<LanguageConfig>::IsPostponeGCSupported() const
214 {
215 return true;
216 }
217
218 template <class LanguageConfig>
MarkObject(ObjectHeader * object)219 void StwGC<LanguageConfig>::MarkObject(ObjectHeader *object)
220 {
221 marker_.Mark(object);
222 }
223
224 template <class LanguageConfig>
UnMarkObject(ObjectHeader * objectHeader)225 void StwGC<LanguageConfig>::UnMarkObject([[maybe_unused]] ObjectHeader *objectHeader)
226 {
227 LOG(FATAL, GC) << "UnMarkObject for STW GC shouldn't be called";
228 }
229
230 template <class LanguageConfig>
MarkReferences(GCMarkingStackType * references,GCPhase gcPhase)231 void StwGC<LanguageConfig>::MarkReferences(GCMarkingStackType *references, [[maybe_unused]] GCPhase gcPhase)
232 {
233 trace::ScopedTrace scopedTrace(__FUNCTION__);
234 ASSERT(gcPhase == GCPhase::GC_PHASE_MARK);
235 LOG_DEBUG_GC << "Start marking " << references->Size() << " references";
236 MarkStack(references);
237 }
238
239 template <class LanguageConfig>
IsMarked(const ObjectHeader * object) const240 bool StwGC<LanguageConfig>::IsMarked(const ObjectHeader *object) const
241 {
242 return marker_.IsMarked(object);
243 }
244
245 TEMPLATE_CLASS_LANGUAGE_CONFIG(StwGC);
246 TEMPLATE_CLASS_LANGUAGE_CONFIG(StwGCMarker);
247
248 } // namespace ark::mem
249