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