• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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