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/gc_root.h"
17
18 #include "libpandafile/panda_cache.h"
19 #include "runtime/include/object_header.h"
20 #include "runtime/include/runtime.h"
21 #include "runtime/include/stack_walker-inl.h"
22 #include "runtime/mem/refstorage/reference_storage.h"
23 #include "runtime/mem/gc/card_table-inl.h"
24 #include "runtime/mem/gc/gc.h"
25 #include "runtime/mem/gc/gc_root_type.h"
26 #include "runtime/mem/object_helpers.h"
27 #include "runtime/mem/refstorage/global_object_storage.h"
28 #include "runtime/include/panda_vm.h"
29
30 namespace ark::mem {
31
GCRoot(RootType type,ObjectHeader * obj)32 GCRoot::GCRoot(RootType type, ObjectHeader *obj)
33 {
34 type_ = type;
35 fromObject_ = nullptr;
36 object_ = obj;
37 }
38
GCRoot(RootType type,ObjectHeader * fromObject,ObjectHeader * obj)39 GCRoot::GCRoot(RootType type, ObjectHeader *fromObject, ObjectHeader *obj)
40 {
41 ASSERT((fromObject != nullptr && type == RootType::ROOT_TENURED) || type != RootType::ROOT_TENURED);
42 type_ = type;
43 fromObject_ = fromObject;
44 object_ = obj;
45 }
46
GetType() const47 RootType GCRoot::GetType() const
48 {
49 return type_;
50 }
51
GetObjectHeader() const52 ObjectHeader *GCRoot::GetObjectHeader() const
53 {
54 return object_;
55 }
56
GetFromObjectHeader() const57 ObjectHeader *GCRoot::GetFromObjectHeader() const
58 {
59 ASSERT((fromObject_ != nullptr && type_ == RootType::ROOT_TENURED) || type_ != RootType::ROOT_TENURED);
60 return fromObject_;
61 }
62
operator <<(std::ostream & os,const GCRoot & root)63 std::ostream &operator<<(std::ostream &os, const GCRoot &root)
64 {
65 switch (root.GetType()) {
66 case RootType::ROOT_CLASS:
67 os << "ROOT CLASS";
68 break;
69 case RootType::ROOT_FRAME:
70 os << "ROOT FRAME";
71 break;
72 case RootType::ROOT_THREAD:
73 os << "ROOT THREAD";
74 break;
75 case RootType::ROOT_TENURED:
76 os << "ROOT TENURED";
77 break;
78 case RootType::ROOT_NATIVE_GLOBAL:
79 os << "ROOT NATIVE_GLOBAL";
80 break;
81 case RootType::ROOT_NATIVE_LOCAL:
82 os << "ROOT NATIVE_LOCAL";
83 break;
84 case RootType::ROOT_AOT_STRING_SLOT:
85 os << "ROOT AOT_STRING_SLOT";
86 break;
87 case RootType::ROOT_UNKNOWN:
88 default:
89 LOG(FATAL, GC) << "ROOT UNKNOWN";
90 break;
91 }
92 os << std::hex << " " << root.GetObjectHeader() << std::endl;
93 return os;
94 }
95
96 template <class LanguageConfig>
VisitNonHeapRoots(const GCRootVisitor & gcRootVisitor,VisitGCRootFlags flags) const97 void RootManager<LanguageConfig>::VisitNonHeapRoots(const GCRootVisitor &gcRootVisitor, VisitGCRootFlags flags) const
98 {
99 VisitLocalRoots(gcRootVisitor);
100 VisitClassRoots(gcRootVisitor, flags);
101 VisitAotStringRoots(gcRootVisitor, flags);
102 VisitClassLinkerContextRoots(gcRootVisitor);
103 VisitVmRoots(gcRootVisitor);
104 auto *storage = vm_->GetGlobalObjectStorage();
105 if (storage != nullptr) {
106 storage->VisitObjects(gcRootVisitor, mem::RootType::ROOT_NATIVE_GLOBAL);
107 }
108 }
109
110 template <class LanguageConfig>
VisitCardTableRoots(CardTable * cardTable,ObjectAllocatorBase * allocator,GCRootVisitor rootVisitor,MemRangeChecker rangeChecker,ObjectChecker rangeObjectChecker,ObjectChecker fromObjectChecker,uint32_t processedFlag) const111 void RootManager<LanguageConfig>::VisitCardTableRoots(CardTable *cardTable, ObjectAllocatorBase *allocator,
112 GCRootVisitor rootVisitor, MemRangeChecker rangeChecker,
113 ObjectChecker rangeObjectChecker, ObjectChecker fromObjectChecker,
114 uint32_t processedFlag) const
115 {
116 cardTable->VisitMarked(
117 [&allocator, &rootVisitor, &rangeChecker, &rangeObjectChecker, &fromObjectChecker,
118 &cardTable](MemRange memRange) {
119 if (rangeChecker(memRange)) {
120 auto objectsInRangeVisitor = [&rootVisitor, &rangeObjectChecker,
121 &fromObjectChecker](ObjectHeader *objectHeader) {
122 auto traverseObjectInRange = [&rootVisitor, &rangeObjectChecker](ObjectHeader *fromObject,
123 ObjectHeader *objectToTraverse) {
124 if (rangeObjectChecker(objectToTraverse)) {
125 // The weak references from dynobjects should not be regarded as roots.
126 TaggedValue value(objectToTraverse);
127 if (!value.IsWeak()) {
128 rootVisitor(GCRoot(RootType::ROOT_TENURED, fromObject, objectToTraverse));
129 }
130 }
131 };
132 if (objectHeader->ClassAddr<BaseClass>() != nullptr && fromObjectChecker(objectHeader)) {
133 // The class may be null in the situation when a new object is allocated in the card
134 // we are visiting now, but the class is not set yet.
135 ObjectHelpers<LanguageConfig::LANG_TYPE>::TraverseAllObjects(objectHeader,
136 traverseObjectInRange);
137 }
138 };
139 allocator->IterateOverObjectsInRange(memRange, objectsInRangeVisitor);
140 } else {
141 auto *card = cardTable->GetCardPtr(memRange.GetStartAddress());
142 // Use SetCard instead of MarkCard because the card can be IsProcessed
143 card->SetCard(CardTable::Card::GetMarkedValue());
144 }
145 },
146 processedFlag);
147 }
148
149 template <class LanguageConfig>
VisitRootsForThread(ManagedThread * thread,const GCRootVisitor & gcRootVisitor) const150 void RootManager<LanguageConfig>::VisitRootsForThread(ManagedThread *thread, const GCRootVisitor &gcRootVisitor) const
151 {
152 LOG(DEBUG, GC) << "Start collecting roots for thread " << thread->GetId();
153
154 thread->VisitGCRoots([&gcRootVisitor](ObjectHeader *obj) {
155 LOG(DEBUG, GC) << " Found root for thread" << GetDebugInfoAboutObject(obj);
156 gcRootVisitor({RootType::ROOT_THREAD, obj});
157 });
158 LOG(DEBUG, GC) << "Finish collecting roots for thread " << thread->GetId();
159 }
160
161 template <class LanguageConfig>
VisitLocalRoots(const GCRootVisitor & gcRootVisitor) const162 void RootManager<LanguageConfig>::VisitLocalRoots(const GCRootVisitor &gcRootVisitor) const
163 {
164 auto threadVisitor = [this, &gcRootVisitor](ManagedThread *thread) {
165 VisitRootsForThread(thread, gcRootVisitor);
166 for (auto stack = StackWalker::Create(thread); stack.HasFrame(); stack.NextFrame()) {
167 LOG(DEBUG, GC) << " VisitRoots frame " << std::hex << stack.GetFp();
168 stack.IterateObjects([this, &gcRootVisitor](auto &vreg) {
169 this->VisitRegisterRoot(vreg, gcRootVisitor);
170 return true;
171 });
172 }
173 return true;
174 };
175 vm_->GetThreadManager()->EnumerateThreads(threadVisitor);
176 }
177
178 template <class LanguageConfig>
179 template <class VRegRef>
VisitRegisterRoot(const VRegRef & vRegister,const GCRootVisitor & gcRootVisitor) const180 void RootManager<LanguageConfig>::VisitRegisterRoot(const VRegRef &vRegister, const GCRootVisitor &gcRootVisitor) const
181 {
182 if (UNLIKELY(vRegister.HasObject())) {
183 ObjectHeader *objectHeader = vRegister.GetReference();
184 if (objectHeader != nullptr) {
185 LOG(DEBUG, GC) << " Found root for register" << GetDebugInfoAboutObject(objectHeader);
186 gcRootVisitor({RootType::ROOT_FRAME, objectHeader});
187 }
188 }
189 }
190
191 template <class LanguageConfig>
VisitVmRoots(const GCRootVisitor & gcRootVisitor) const192 void RootManager<LanguageConfig>::VisitVmRoots(const GCRootVisitor &gcRootVisitor) const
193 {
194 vm_->VisitVmRoots(gcRootVisitor);
195 }
196
197 template <class LanguageConfig>
VisitAotStringRoots(const GCRootVisitor & gcRootVisitor,VisitGCRootFlags flags) const198 void RootManager<LanguageConfig>::VisitAotStringRoots(const GCRootVisitor &gcRootVisitor, VisitGCRootFlags flags) const
199 {
200 trace::ScopedTrace scopedTrace(__FUNCTION__);
201 LOG(DEBUG, GC) << "Start collecting AOT string slot roots";
202 Runtime::GetCurrent()->GetClassLinker()->GetAotManager()->VisitAotStringRoots(
203 [&gcRootVisitor](ObjectHeader **slot) {
204 gcRootVisitor({RootType::ROOT_AOT_STRING_SLOT, *slot});
205 },
206 (flags & VisitGCRootFlags::ACCESS_ROOT_AOT_STRINGS_ONLY_YOUNG) != 0);
207 LOG(DEBUG, GC) << "Finish collecting AOT string slot roots";
208 }
209
210 template <class LanguageConfig>
UpdateAotStringRoots()211 void RootManager<LanguageConfig>::UpdateAotStringRoots()
212 {
213 trace::ScopedTrace scopedTrace(__FUNCTION__);
214 LOG(DEBUG, GC) << "=== AOT string slot roots update. BEGIN ===";
215 auto hm = vm_->GetHeapManager();
216 Runtime::GetCurrent()->GetClassLinker()->GetAotManager()->UpdateAotStringRoots(
217 [](ObjectHeader **root) {
218 auto rootValue = *root;
219 if (rootValue->IsForwarded()) {
220 *root = ::ark::mem::GetForwardAddress(rootValue);
221 }
222 },
223 [&hm](const ObjectHeader *root) { return hm->IsObjectInYoungSpace(root); });
224 LOG(DEBUG, GC) << "=== AOT string slot roots update. END ===";
225 }
226
227 template <class LanguageConfig>
UpdateVmRefs()228 void RootManager<LanguageConfig>::UpdateVmRefs()
229 {
230 vm_->UpdateVmRefs();
231 }
232
233 template <class LanguageConfig>
UpdateGlobalObjectStorage()234 void RootManager<LanguageConfig>::UpdateGlobalObjectStorage()
235 {
236 auto globalStorage = vm_->GetGlobalObjectStorage();
237 if (globalStorage != nullptr) {
238 globalStorage->UpdateMovedRefs();
239 }
240 }
241
242 template <class LanguageConfig>
VisitClassRoots(const GCRootVisitor & gcRootVisitor,VisitGCRootFlags flags) const243 void RootManager<LanguageConfig>::VisitClassRoots(const GCRootVisitor &gcRootVisitor, VisitGCRootFlags flags) const
244 {
245 LOG(DEBUG, GC) << "Start collecting roots for classes";
246 auto classLinker = Runtime::GetCurrent()->GetClassLinker();
247 auto classRootVisitor = [&gcRootVisitor](Class *cls) {
248 gcRootVisitor({RootType::ROOT_CLASS, cls->GetManagedObject()});
249 LOG(DEBUG, GC) << " Found class root " << GetDebugInfoAboutObject(cls->GetManagedObject());
250 return true;
251 };
252 auto *extension = classLinker->GetExtension(LanguageConfig::LANG);
253 extension->EnumerateClasses(classRootVisitor, flags);
254
255 LOG(DEBUG, GC) << "Finish collecting roots for classes";
256 }
257
258 template <class LanguageConfig>
UpdateThreadLocals()259 void RootManager<LanguageConfig>::UpdateThreadLocals()
260 {
261 LOG(DEBUG, GC) << "=== ThreadLocals Update moved. BEGIN ===";
262 vm_->GetThreadManager()->EnumerateThreads([](ManagedThread *thread) {
263 thread->UpdateGCRoots();
264 return true;
265 });
266 LOG(DEBUG, GC) << "=== ThreadLocals Update moved. END ===";
267 }
268
269 template <class LanguageConfig>
VisitClassLinkerContextRoots(const GCRootVisitor & gcRootVisitor) const270 void RootManager<LanguageConfig>::VisitClassLinkerContextRoots(const GCRootVisitor &gcRootVisitor) const
271 {
272 LOG(DEBUG, GC) << "Start collecting roots for class linker contexts";
273 auto classLinker = Runtime::GetCurrent()->GetClassLinker();
274 auto *extension = classLinker->GetExtension(LanguageConfig::LANG);
275 extension->EnumerateContexts([&gcRootVisitor](ClassLinkerContext *ctx) {
276 ctx->VisitGCRoots([&gcRootVisitor](ObjectHeader *obj) {
277 LOG(DEBUG, GC) << " Found root for class linker context " << GetDebugInfoAboutObject(obj);
278 gcRootVisitor({RootType::ROOT_CLASS_LINKER, obj});
279 });
280 return true;
281 });
282 LOG(DEBUG, GC) << "Finish collecting roots for class linker contexts";
283 }
284
285 template <class LanguageConfig>
UpdateClassLinkerContextRoots()286 void RootManager<LanguageConfig>::UpdateClassLinkerContextRoots()
287 {
288 auto classLinker = Runtime::GetCurrent()->GetClassLinker();
289 auto *extension = classLinker->GetExtension(LanguageConfig::LANG);
290 extension->EnumerateContexts([](ClassLinkerContext *ctx) {
291 ctx->UpdateGCRoots();
292 return true;
293 });
294 }
295
operator &(VisitGCRootFlags left,VisitGCRootFlags right)296 uint32_t operator&(VisitGCRootFlags left, VisitGCRootFlags right)
297 {
298 return static_cast<uint32_t>(left) & static_cast<uint32_t>(right);
299 }
300
operator |(VisitGCRootFlags left,VisitGCRootFlags right)301 VisitGCRootFlags operator|(VisitGCRootFlags left, VisitGCRootFlags right)
302 {
303 return static_cast<VisitGCRootFlags>(static_cast<uint32_t>(left) | static_cast<uint32_t>(right));
304 }
305
306 TEMPLATE_CLASS_LANGUAGE_CONFIG(RootManager);
307
308 } // namespace ark::mem
309