1 /*
2 * Copyright (c) 2025 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 "common_components/heap/allocator/fix_heap.h"
17
18 #include "common_components/heap/ark_collector/ark_collector.h"
19 #include "common_runtime/hooks.h"
20
21 namespace common {
22
CollectFixHeapTasks(FixHeapTaskList & taskList,RegionList & list,FixRegionType type)23 void FixHeapWorker::CollectFixHeapTasks(FixHeapTaskList &taskList, RegionList &list, FixRegionType type)
24 {
25 list.VisitAllRegions([&taskList, type](RegionDesc *region) { taskList.emplace_back(region, type); });
26 }
27
FixOldRegion(RegionDesc * region)28 void FixHeapWorker::FixOldRegion(RegionDesc *region)
29 {
30 auto visitFunc = [this, ®ion](BaseObject *object) {
31 DLOG(FIX, "fix: old obj %p<%p>(%zu)", object, object->GetTypeInfo(), object->GetSize());
32 collector_->FixObjectRefFields(object);
33 };
34 region->VisitRememberSet(visitFunc);
35 }
36
FixRecentOldRegion(RegionDesc * region)37 void FixHeapWorker::FixRecentOldRegion(RegionDesc *region)
38 {
39 auto visitFunc = [this, ®ion](BaseObject *object) {
40 DLOG(FIX, "fix: old obj %p<%p>(%zu)", object, object->GetTypeInfo(), object->GetSize());
41 collector_->FixObjectRefFields(object);
42 };
43 region->VisitRememberSetBeforeCopy(visitFunc);
44 }
45
FixToRegion(RegionDesc * region)46 void FixHeapWorker::FixToRegion(RegionDesc *region)
47 {
48 region->VisitAllObjects([this](BaseObject *object) { collector_->FixObjectRefFields(object); });
49 }
50
51 template <FixHeapWorker::DeadObjectHandlerType type>
FixRegion(RegionDesc * region)52 void FixHeapWorker::FixRegion(RegionDesc *region)
53 {
54 size_t cellCount = 0;
55 if constexpr (type == FixHeapWorker::COLLECT_FIXED_PINNED) {
56 cellCount = region->GetRegionCellCount();
57 }
58
59 region->VisitAllObjects([this, region, cellCount](BaseObject *object) {
60 if (collector_->IsSurvivedObject(object)) {
61 collector_->FixObjectRefFields(object);
62 } else {
63 if constexpr (type == FixHeapWorker::FILL_FREE) {
64 FillFreeObject(object, RegionSpace::GetAllocSize(*object));
65 } else if constexpr (type == FixHeapWorker::COLLECT_FIXED_PINNED) {
66 result_.fixedPinnedGarbages.emplace_back(region, object, cellCount);
67 } else if constexpr (type == FixHeapWorker::COLLECT_PINNED) {
68 result_.pinnedGarbages.emplace_back(object, RegionSpace::GetAllocSize(*object));
69 } else if constexpr (type == FixHeapWorker::IGNORED) {
70 /* Ignore */
71 }
72 DLOG(FIX, "fix: skip dead obj %p<%p>(%zu)", object, object->GetTypeInfo(), object->GetSize());
73 }
74 });
75 }
76
77 template <FixHeapWorker::DeadObjectHandlerType type>
FixRecentRegion(RegionDesc * region)78 void FixHeapWorker::FixRecentRegion(RegionDesc *region)
79 {
80 size_t cellCount = 0;
81 if constexpr (type == FixHeapWorker::COLLECT_FIXED_PINNED) {
82 cellCount = region->GetRegionCellCount();
83 }
84
85 region->VisitAllObjectsBeforeCopy([this, region, cellCount](BaseObject *object) {
86 if (region->IsNewObjectSinceMarking(object) || collector_->IsSurvivedObject(object)) {
87 collector_->FixObjectRefFields(object);
88 } else { // handle dead objects in tl-regions for concurrent gc.
89 if constexpr (type == FixHeapWorker::FILL_FREE) {
90 FillFreeObject(object, RegionSpace::GetAllocSize(*object));
91 } else if constexpr (type == FixHeapWorker::COLLECT_FIXED_PINNED) {
92 result_.fixedPinnedGarbages.emplace_back(region, object, cellCount);
93 } else if constexpr (type == FixHeapWorker::COLLECT_PINNED) {
94 result_.pinnedGarbages.emplace_back(object, RegionSpace::GetAllocSize(*object));
95 } else if constexpr (type == FixHeapWorker::IGNORED) {
96 /* Ignore */
97 }
98 DLOG(FIX, "skip dead obj %p<%p>(%zu)", object, object->GetTypeInfo(), object->GetSize());
99 }
100 });
101 }
102
Run(uint32_t threadIndex)103 bool FixHeapWorker::Run([[maybe_unused]] uint32_t threadIndex)
104 {
105 ThreadLocal::SetThreadType(ThreadType::GC_THREAD);
106 auto *task = getNextTask_();
107 while (task != nullptr) {
108 DispatchRegionFixTask(task);
109 task = getNextTask_();
110 }
111 ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
112 monitor_.NotifyFinishOne();
113 return true;
114 }
115
DispatchRegionFixTask(FixHeapTask * task)116 void FixHeapWorker::DispatchRegionFixTask(FixHeapTask *task)
117 {
118 result_.numProcessedRegions += 1;
119 RegionDesc *region = task->region;
120 switch (task->type) {
121 case FIX_OLD_REGION:
122 FixOldRegion(region);
123 break;
124 case FIX_RECENT_OLD_REGION:
125 FixRecentOldRegion(region);
126 break;
127 case FIX_RECENT_REGION:
128 if (region->IsFixedRegion()) {
129 FixRecentRegion<COLLECT_FIXED_PINNED>(region);
130 } else if (region->IsPinnedRegion()) {
131 FixRecentRegion<COLLECT_PINNED>(region);
132 } else if (region->IsLargeRegion()) {
133 FixRecentRegion<IGNORED>(region);
134 } else {
135 FixRecentRegion<FILL_FREE>(region);
136 }
137 break;
138 case FIX_REGION:
139 if (region->IsFixedRegion()) {
140 FixRegion<COLLECT_FIXED_PINNED>(region);
141 } else if (region->IsPinnedRegion()) {
142 FixRegion<COLLECT_PINNED>(region);
143 } else if (region->IsLargeRegion()) {
144 FixRegion<IGNORED>(region);
145 } else {
146 FixRegion<FILL_FREE>(region);
147 }
148 break;
149 case FIX_TO_REGION:
150 FixToRegion(region);
151 break;
152 default:
153 UNREACHABLE();
154 }
155 }
156
157 std::stack<std::pair<RegionList *, RegionDesc *>> PostFixHeapWorker::emptyRegionsToCollect {};
158
PostClearTask()159 void PostFixHeapWorker::PostClearTask()
160 {
161 for (auto [region, object, cellCount] : result_.fixedPinnedGarbages) {
162 region->CollectPinnedGarbage(object, cellCount);
163 }
164 for (auto [object, size] : result_.pinnedGarbages) {
165 FillFreeObject(object, size);
166 }
167 DLOG(FIX, "Fix heap worker processed %d Regions, %d fixedPinnedGarbages, %d pinnedGarbages",
168 result_.numProcessedRegions, result_.fixedPinnedGarbages.size(), result_.pinnedGarbages.size());
169 }
170
Run(uint32_t threadIndex)171 bool PostFixHeapWorker::Run([[maybe_unused]] uint32_t threadIndex)
172 {
173 ThreadLocal::SetThreadType(ThreadType::GC_THREAD);
174 PostClearTask();
175 ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
176 monitor_.NotifyFinishOne();
177 return true;
178 }
179
AddEmptyRegionToCollectDuringPostFix(RegionList * list,RegionDesc * region)180 void PostFixHeapWorker::AddEmptyRegionToCollectDuringPostFix(RegionList *list, RegionDesc *region)
181 {
182 PostFixHeapWorker::emptyRegionsToCollect.emplace(list, region);
183 }
184
CollectEmptyRegions()185 void PostFixHeapWorker::CollectEmptyRegions()
186 {
187 RegionSpace &theAllocator = reinterpret_cast<RegionSpace &>(Heap::GetHeap().GetAllocator());
188 RegionManager ®ionManager = theAllocator.GetRegionManager();
189 GCStats &stats = Heap::GetHeap().GetCollector().GetGCStats();
190 size_t garbageSize = 0;
191
192 while (!PostFixHeapWorker::emptyRegionsToCollect.empty()) {
193 auto [list, del] = PostFixHeapWorker::emptyRegionsToCollect.top();
194 PostFixHeapWorker::emptyRegionsToCollect.pop();
195
196 list->DeleteRegion(del);
197 garbageSize += regionManager.CollectRegion(del);
198 }
199 stats.pinnedGarbageSize += garbageSize;
200 }
201
202 }; // namespace common
203