• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 panda::mem {
31 
GCRoot(RootType type,ObjectHeader * obj)32 GCRoot::GCRoot(RootType type, ObjectHeader *obj)
33 {
34     type_ = type;
35     from_object_ = nullptr;
36     object_ = obj;
37 }
38 
GCRoot(RootType type,ObjectHeader * from_object,ObjectHeader * obj)39 GCRoot::GCRoot(RootType type, ObjectHeader *from_object, ObjectHeader *obj)
40 {
41     ASSERT((from_object != nullptr && type == RootType::ROOT_TENURED) || type != RootType::ROOT_TENURED);
42     type_ = type;
43     from_object_ = from_object;
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((from_object_ != nullptr && type_ == RootType::ROOT_TENURED) || type_ != RootType::ROOT_TENURED);
60     return from_object_;
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 & gc_root_visitor,VisitGCRootFlags flags) const97 void RootManager<LanguageConfig>::VisitNonHeapRoots(const GCRootVisitor &gc_root_visitor, VisitGCRootFlags flags) const
98 {
99     VisitLocalRoots(gc_root_visitor);
100     VisitClassRoots(gc_root_visitor, flags);
101     VisitAotStringRoots(gc_root_visitor, flags);
102     VisitClassLinkerContextRoots(gc_root_visitor);
103     VisitVmRoots(gc_root_visitor);
104     auto *storage = vm_->GetGlobalObjectStorage();
105     if (storage != nullptr) {
106         storage->VisitObjects(gc_root_visitor, mem::RootType::ROOT_NATIVE_GLOBAL);
107     }
108 }
109 
110 template <class LanguageConfig>
VisitCardTableRoots(CardTable * card_table,ObjectAllocatorBase * allocator,GCRootVisitor root_visitor,MemRangeChecker range_checker,ObjectChecker range_object_checker,ObjectChecker from_object_checker,uint32_t processed_flag) const111 void RootManager<LanguageConfig>::VisitCardTableRoots(CardTable *card_table, ObjectAllocatorBase *allocator,
112                                                       GCRootVisitor root_visitor, MemRangeChecker range_checker,
113                                                       ObjectChecker range_object_checker,
114                                                       ObjectChecker from_object_checker, uint32_t processed_flag) const
115 {
116     card_table->VisitMarked(
117         [&allocator, &root_visitor, &range_checker, &range_object_checker, &from_object_checker,
118          &card_table](MemRange mem_range) {
119             if (range_checker(mem_range)) {
120                 auto objects_in_range_visitor = [&root_visitor, &range_object_checker,
121                                                  &from_object_checker](ObjectHeader *object_header) {
122                     auto traverse_object_in_range = [&root_visitor, &range_object_checker](
123                                                         ObjectHeader *from_object, ObjectHeader *object_to_traverse) {
124                         if (range_object_checker(object_to_traverse)) {
125                             // The weak references from dynobjects should not be regarded as roots.
126                             TaggedValue value(object_to_traverse);
127                             if (!value.IsWeak()) {
128                                 root_visitor(GCRoot(RootType::ROOT_TENURED, from_object, object_to_traverse));
129                             }
130                         }
131                     };
132                     if (object_header->ClassAddr<BaseClass>() != nullptr && from_object_checker(object_header)) {
133                         // The class may be null in the situation when a new objct is allocated in the card
134                         // we are visiting now, but the class is not set yet.
135                         ObjectHelpers<LanguageConfig::LANG_TYPE>::TraverseAllObjects(object_header,
136                                                                                      traverse_object_in_range);
137                     }
138                 };
139                 allocator->IterateOverObjectsInRange(mem_range, objects_in_range_visitor);
140             } else {
141                 card_table->MarkCard(mem_range.GetStartAddress());
142             }
143         },
144         processed_flag);
145 }
146 
147 template <class LanguageConfig>
VisitRootsForThread(ManagedThread * thread,const GCRootVisitor & gc_root_visitor) const148 void RootManager<LanguageConfig>::VisitRootsForThread(ManagedThread *thread, const GCRootVisitor &gc_root_visitor) const
149 {
150     LOG(DEBUG, GC) << "Start collecting roots for thread " << thread->GetId();
151 
152     thread->VisitGCRoots([&gc_root_visitor](ObjectHeader *obj) {
153         LOG(DEBUG, GC) << " Found root for thread" << GetDebugInfoAboutObject(obj);
154         gc_root_visitor({RootType::ROOT_THREAD, obj});
155     });
156     LOG(DEBUG, GC) << "Finish collecting roots for thread " << thread->GetId();
157 }
158 
159 template <class LanguageConfig>
VisitLocalRoots(const GCRootVisitor & gc_root_visitor) const160 void RootManager<LanguageConfig>::VisitLocalRoots(const GCRootVisitor &gc_root_visitor) const
161 {
162     auto thread_visitor = [this, &gc_root_visitor](ManagedThread *thread) {
163         VisitRootsForThread(thread, gc_root_visitor);
164         for (auto stack = StackWalker::Create(thread); stack.HasFrame(); stack.NextFrame()) {
165             LOG(DEBUG, GC) << " VisitRoots frame " << std::hex << stack.GetFp();
166             stack.IterateObjects([this, &gc_root_visitor](auto &vreg) {
167                 this->VisitRegisterRoot(vreg, gc_root_visitor);
168                 return true;
169             });
170         }
171         return true;
172     };
173     if constexpr (LanguageConfig::MT_MODE == MT_MODE_MULTI) {  // NOLINT
174         vm_->GetThreadManager()->EnumerateThreads(thread_visitor);
175     } else {  // NOLINT
176         thread_visitor(vm_->GetAssociatedThread());
177     }
178 }
179 
180 template <class LanguageConfig>
181 template <class VRegRef>
VisitRegisterRoot(const VRegRef & v_register,const GCRootVisitor & gc_root_visitor) const182 void RootManager<LanguageConfig>::VisitRegisterRoot(const VRegRef &v_register,
183                                                     const GCRootVisitor &gc_root_visitor) const
184 {
185     if (UNLIKELY(v_register.HasObject())) {
186         ObjectHeader *object_header = v_register.GetReference();
187         if (object_header != nullptr) {
188             LOG(DEBUG, GC) << " Found root for register" << GetDebugInfoAboutObject(object_header);
189             gc_root_visitor({RootType::ROOT_FRAME, object_header});
190         }
191     }
192 }
193 
194 template <class LanguageConfig>
VisitVmRoots(const GCRootVisitor & gc_root_visitor) const195 void RootManager<LanguageConfig>::VisitVmRoots(const GCRootVisitor &gc_root_visitor) const
196 {
197     vm_->VisitVmRoots(gc_root_visitor);
198 }
199 
200 template <class LanguageConfig>
VisitAotStringRoots(const GCRootVisitor & gc_root_visitor,VisitGCRootFlags flags) const201 void RootManager<LanguageConfig>::VisitAotStringRoots(const GCRootVisitor &gc_root_visitor,
202                                                       VisitGCRootFlags flags) const
203 {
204     trace::ScopedTrace scoped_trace(__FUNCTION__);
205     LOG(DEBUG, GC) << "Start collecting AOT string slot roots";
206     Runtime::GetCurrent()->GetClassLinker()->GetAotManager()->VisitAotStringRoots(
207         [&gc_root_visitor](ObjectHeader **slot) {
208             gc_root_visitor({RootType::ROOT_AOT_STRING_SLOT, *slot});
209         },
210         (flags & VisitGCRootFlags::ACCESS_ROOT_AOT_STRINGS_ONLY_YOUNG) != 0);
211     LOG(DEBUG, GC) << "Finish collecting AOT string slot roots";
212 }
213 
214 template <class LanguageConfig>
UpdateAotStringRoots()215 void RootManager<LanguageConfig>::UpdateAotStringRoots()
216 {
217     trace::ScopedTrace scoped_trace(__FUNCTION__);
218     LOG(DEBUG, GC) << "=== AOT string slot roots update. BEGIN ===";
219     auto oa = Thread::GetCurrent()->GetVM()->GetHeapManager()->GetObjectAllocator().AsObjectAllocator();
220     Runtime::GetCurrent()->GetClassLinker()->GetAotManager()->UpdateAotStringRoots(
221         [](ObjectHeader **root) {
222             auto root_value = *root;
223             if (root_value->IsForwarded()) {
224                 *root = ::panda::mem::GetForwardAddress(root_value);
225             }
226         },
227         [&oa](const ObjectHeader *root) {
228             return oa->HasYoungSpace() && oa->IsAddressInYoungSpace(reinterpret_cast<uintptr_t>(root));
229         });
230     LOG(DEBUG, GC) << "=== AOT string slot roots update. END ===";
231 }
232 
233 template <class LanguageConfig>
UpdateVmRefs()234 void RootManager<LanguageConfig>::UpdateVmRefs()
235 {
236     vm_->UpdateVmRefs();
237 }
238 
239 template <class LanguageConfig>
UpdateGlobalObjectStorage()240 void RootManager<LanguageConfig>::UpdateGlobalObjectStorage()
241 {
242     auto global_storage = vm_->GetGlobalObjectStorage();
243     if (global_storage != nullptr) {
244         global_storage->UpdateMovedRefs();
245     }
246 }
247 
248 template <class LanguageConfig>
VisitClassRoots(const GCRootVisitor & gc_root_visitor,VisitGCRootFlags flags) const249 void RootManager<LanguageConfig>::VisitClassRoots(const GCRootVisitor &gc_root_visitor, VisitGCRootFlags flags) const
250 {
251     LOG(DEBUG, GC) << "Start collecting roots for classes";
252     auto class_linker = Runtime::GetCurrent()->GetClassLinker();
253     auto class_root_visitor = [&gc_root_visitor](Class *cls) {
254         gc_root_visitor({RootType::ROOT_CLASS, cls->GetManagedObject()});
255         LOG(DEBUG, GC) << " Found class root " << GetDebugInfoAboutObject(cls->GetManagedObject());
256         return true;
257     };
258     auto *extension = class_linker->GetExtension(LanguageConfig::LANG);
259     extension->EnumerateClasses(class_root_visitor, flags);
260 
261     // TODO(maksenov): Remove after supporting multiple GC instances
262     if (LanguageConfig::LANG != panda_file::SourceLang::PANDA_ASSEMBLY &&
263         class_linker->HasExtension(panda_file::SourceLang::PANDA_ASSEMBLY)) {
264         class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)->EnumerateClasses(class_root_visitor, flags);
265     }
266 
267     LOG(DEBUG, GC) << "Finish collecting roots for classes";
268 }
269 
270 template <class LanguageConfig>
UpdateThreadLocals()271 void RootManager<LanguageConfig>::UpdateThreadLocals()
272 {
273     LOG(DEBUG, GC) << "=== ThreadLocals Update moved. BEGIN ===";
274     if constexpr (LanguageConfig::MT_MODE == MT_MODE_MULTI) {  // NOLINT
275         vm_->GetThreadManager()->EnumerateThreads([](MTManagedThread *thread) {
276             thread->UpdateGCRoots();
277             return true;
278         });
279     } else {  // NOLINT
280         vm_->GetAssociatedThread()->UpdateGCRoots();
281     }
282     LOG(DEBUG, GC) << "=== ThreadLocals Update moved. END ===";
283 }
284 
285 template <class LanguageConfig>
VisitClassLinkerContextRoots(const GCRootVisitor & gc_root_visitor) const286 void RootManager<LanguageConfig>::VisitClassLinkerContextRoots(const GCRootVisitor &gc_root_visitor) const
287 {
288     LOG(DEBUG, GC) << "Start collecting roots for class linker contexts";
289     auto class_linker = Runtime::GetCurrent()->GetClassLinker();
290     auto *extension = class_linker->GetExtension(LanguageConfig::LANG);
291     extension->EnumerateContexts([&gc_root_visitor](ClassLinkerContext *ctx) {
292         ctx->VisitGCRoots([&gc_root_visitor](ObjectHeader *obj) {
293             LOG(DEBUG, GC) << " Found root for class linker context " << GetDebugInfoAboutObject(obj);
294             gc_root_visitor({RootType::ROOT_CLASS_LINKER, obj});
295         });
296         return true;
297     });
298     LOG(DEBUG, GC) << "Finish collecting roots for class linker contexts";
299 }
300 
301 template <class LanguageConfig>
UpdateClassLinkerContextRoots()302 void RootManager<LanguageConfig>::UpdateClassLinkerContextRoots()
303 {
304     auto class_linker = Runtime::GetCurrent()->GetClassLinker();
305     auto *extension = class_linker->GetExtension(LanguageConfig::LANG);
306     extension->EnumerateContexts([](ClassLinkerContext *ctx) {
307         ctx->UpdateGCRoots();
308         return true;
309     });
310 }
311 
operator &(VisitGCRootFlags left,VisitGCRootFlags right)312 uint32_t operator&(VisitGCRootFlags left, VisitGCRootFlags right)
313 {
314     return static_cast<uint32_t>(left) & static_cast<uint32_t>(right);
315 }
316 
operator |(VisitGCRootFlags left,VisitGCRootFlags right)317 VisitGCRootFlags operator|(VisitGCRootFlags left, VisitGCRootFlags right)
318 {
319     return static_cast<VisitGCRootFlags>(static_cast<uint32_t>(left) | static_cast<uint32_t>(right));
320 }
321 
322 TEMPLATE_CLASS_LANGUAGE_CONFIG(RootManager);
323 
324 }  // namespace panda::mem
325