• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 "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(const GCRootUpdater & gcRootUpdater)211 void RootManager<LanguageConfig>::UpdateAotStringRoots(const GCRootUpdater &gcRootUpdater)
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         [&gcRootUpdater](ObjectHeader **root) { gcRootUpdater(root); },
218         [&hm](const ObjectHeader *root) { return hm->IsObjectInYoungSpace(root); });
219     LOG(DEBUG, GC) << "=== AOT string slot roots update. END ===";
220 }
221 
222 template <class LanguageConfig>
UpdateVmRefs(const GCRootUpdater & gcRootUpdater)223 void RootManager<LanguageConfig>::UpdateVmRefs(const GCRootUpdater &gcRootUpdater)
224 {
225     vm_->UpdateVmRefs(gcRootUpdater);
226 }
227 
228 template <class LanguageConfig>
UpdateGlobalObjectStorage(const GCRootUpdater & gcRootUpdater)229 void RootManager<LanguageConfig>::UpdateGlobalObjectStorage(const GCRootUpdater &gcRootUpdater)
230 {
231     auto globalStorage = vm_->GetGlobalObjectStorage();
232     if (globalStorage != nullptr) {
233         globalStorage->UpdateMovedRefs(gcRootUpdater);
234     }
235 }
236 
237 template <class LanguageConfig>
VisitClassRoots(const GCRootVisitor & gcRootVisitor,VisitGCRootFlags flags) const238 void RootManager<LanguageConfig>::VisitClassRoots(const GCRootVisitor &gcRootVisitor, VisitGCRootFlags flags) const
239 {
240     LOG(DEBUG, GC) << "Start collecting roots for classes";
241     auto classLinker = Runtime::GetCurrent()->GetClassLinker();
242     auto classRootVisitor = [&gcRootVisitor](Class *cls) {
243         gcRootVisitor({RootType::ROOT_CLASS, cls->GetManagedObject()});
244         LOG(DEBUG, GC) << " Found class root " << GetDebugInfoAboutObject(cls->GetManagedObject());
245         return true;
246     };
247     auto *extension = classLinker->GetExtension(LanguageConfig::LANG);
248     extension->EnumerateClasses(classRootVisitor, flags);
249 
250     LOG(DEBUG, GC) << "Finish collecting roots for classes";
251 }
252 
253 template <class LanguageConfig>
UpdateRefsToMovedObjects(const GCRootUpdater & gcRootUpdater)254 void RootManager<LanguageConfig>::UpdateRefsToMovedObjects(const GCRootUpdater &gcRootUpdater)
255 {
256     auto cb = [this, &gcRootUpdater](ManagedThread *thread) {
257         UpdateRefsInVRegs(thread, gcRootUpdater);
258         return true;
259     };
260     // Update refs in vregs
261     vm_->GetThreadManager()->EnumerateThreads(cb);
262     if constexpr (LanguageConfig::MT_MODE != MT_MODE_SINGLE) {
263         // Update refs inside monitors
264         vm_->GetMonitorPool()->EnumerateMonitors([&gcRootUpdater](Monitor *monitor) {
265             ObjectHeader *objectHeader = monitor->GetObject();
266             if (objectHeader == nullptr) {
267                 return true;
268             }
269             ObjectHeader *newObjectHeader = objectHeader;
270             if (gcRootUpdater(&newObjectHeader)) {
271                 LOG(DEBUG, GC) << "Update monitor " << std::hex << monitor << " object, old val = " << objectHeader
272                                << ", new val = " << newObjectHeader;
273                 monitor->SetObject(reinterpret_cast<ObjectHeader *>(newObjectHeader));
274             }
275             return true;
276         });
277     }
278     if (vm_->UpdateMovedStrings(gcRootUpdater)) {
279         // AOT string slots are pointing to strings from the StringTable,
280         // so we should update it only if StringTable's pointers were updated.
281         UpdateAotStringRoots(gcRootUpdater);
282     }
283     // Update thread locals
284     UpdateThreadLocals(gcRootUpdater);
285     // Update refs in vm
286     UpdateVmRefs(gcRootUpdater);
287     // Update refs in class linker contexts
288     UpdateClassLinkerContextRoots(gcRootUpdater);
289     // Update global refs
290     UpdateGlobalObjectStorage(gcRootUpdater);
291 }
292 
293 template <class LanguageConfig>
UpdateRefsInVRegs(ManagedThread * thread,const GCRootUpdater & gcRootUpdater)294 void RootManager<LanguageConfig>::UpdateRefsInVRegs(ManagedThread *thread, const GCRootUpdater &gcRootUpdater)
295 {
296     LOG(DEBUG, GC) << "Update frames for thread: " << thread->GetId();
297     for (auto pframe = StackWalker::Create(thread); pframe.HasFrame(); pframe.NextFrame()) {
298         LOG(DEBUG, GC) << "Frame for method " << pframe.GetMethod()->GetFullName();
299         auto iterator = [&pframe, &gcRootUpdater](auto &regInfo, auto &vreg) {
300             ObjectHeader *objectHeader = vreg.GetReference();
301             if (objectHeader == nullptr) {
302                 return true;
303             }
304             ObjectHeader *newObjectHeader = objectHeader;
305             if (!gcRootUpdater(&newObjectHeader)) {
306                 return true;
307             }
308             LOG(DEBUG, GC) << "Update vreg, vreg old val = " << objectHeader << ", new val = " << newObjectHeader;
309             LOG_IF(regInfo.IsAccumulator(), DEBUG, GC) << "^ acc reg";
310             if (!pframe.IsCFrame() && regInfo.IsAccumulator()) {
311                 LOG(DEBUG, GC) << "^ acc updated";
312                 vreg.SetReference(newObjectHeader);
313             } else {
314                 pframe.template SetVRegValue<std::is_same_v<decltype(vreg), interpreter::DynamicVRegisterRef &>>(
315                     regInfo, newObjectHeader);
316             }
317             return true;
318         };
319         pframe.IterateObjectsWithInfo(iterator);
320     }
321 }
322 
323 template <class LanguageConfig>
UpdateThreadLocals(const GCRootUpdater & gcRootUpdater)324 void RootManager<LanguageConfig>::UpdateThreadLocals(const GCRootUpdater &gcRootUpdater)
325 {
326     LOG(DEBUG, GC) << "=== ThreadLocals Update moved. BEGIN ===";
327     vm_->GetThreadManager()->EnumerateThreads([&gcRootUpdater](ManagedThread *thread) {
328         thread->UpdateGCRoots(gcRootUpdater);
329         return true;
330     });
331     LOG(DEBUG, GC) << "=== ThreadLocals Update moved. END ===";
332 }
333 
334 template <class LanguageConfig>
VisitClassLinkerContextRoots(const GCRootVisitor & gcRootVisitor) const335 void RootManager<LanguageConfig>::VisitClassLinkerContextRoots(const GCRootVisitor &gcRootVisitor) const
336 {
337     LOG(DEBUG, GC) << "Start collecting roots for class linker contexts";
338     auto classLinker = Runtime::GetCurrent()->GetClassLinker();
339     auto *extension = classLinker->GetExtension(LanguageConfig::LANG);
340     extension->EnumerateContexts([&gcRootVisitor](ClassLinkerContext *ctx) {
341         ctx->VisitGCRoots([&gcRootVisitor](ObjectHeader *obj) {
342             LOG(DEBUG, GC) << " Found root for class linker context " << GetDebugInfoAboutObject(obj);
343             gcRootVisitor({RootType::ROOT_CLASS_LINKER, obj});
344         });
345         return true;
346     });
347     LOG(DEBUG, GC) << "Finish collecting roots for class linker contexts";
348 }
349 
350 template <class LanguageConfig>
UpdateClassLinkerContextRoots(const GCRootUpdater & gcRootUpdater)351 void RootManager<LanguageConfig>::UpdateClassLinkerContextRoots(const GCRootUpdater &gcRootUpdater)
352 {
353     auto classLinker = Runtime::GetCurrent()->GetClassLinker();
354     auto *extension = classLinker->GetExtension(LanguageConfig::LANG);
355     extension->EnumerateContexts([&gcRootUpdater](ClassLinkerContext *ctx) {
356         ctx->UpdateGCRoots(gcRootUpdater);
357         return true;
358     });
359 }
360 
operator &(VisitGCRootFlags left,VisitGCRootFlags right)361 uint32_t operator&(VisitGCRootFlags left, VisitGCRootFlags right)
362 {
363     return static_cast<uint32_t>(left) & static_cast<uint32_t>(right);
364 }
365 
operator |(VisitGCRootFlags left,VisitGCRootFlags right)366 VisitGCRootFlags operator|(VisitGCRootFlags left, VisitGCRootFlags right)
367 {
368     return static_cast<VisitGCRootFlags>(static_cast<uint32_t>(left) | static_cast<uint32_t>(right));
369 }
370 
371 TEMPLATE_CLASS_LANGUAGE_CONFIG(RootManager);
372 
373 }  // namespace ark::mem
374