1 /*
2 * Copyright (c) 2021 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/object_helpers.h"
26 #include "runtime/mem/refstorage/global_object_storage.h"
27 #include "runtime/include/panda_vm.h"
28
29 namespace panda::mem {
30
GCRoot(RootType type,ObjectHeader * obj)31 GCRoot::GCRoot(RootType type, ObjectHeader *obj)
32 {
33 type_ = type;
34 from_object_ = nullptr;
35 object_ = obj;
36 }
37
GCRoot(RootType type,ObjectHeader * from_object,ObjectHeader * obj)38 GCRoot::GCRoot(RootType type, ObjectHeader *from_object, ObjectHeader *obj)
39 {
40 ASSERT((from_object != nullptr && type == RootType::ROOT_TENURED) || type != RootType::ROOT_TENURED);
41 type_ = type;
42 from_object_ = from_object;
43 object_ = obj;
44 }
45
GetType() const46 RootType GCRoot::GetType() const
47 {
48 return type_;
49 }
50
GetObjectHeader() const51 ObjectHeader *GCRoot::GetObjectHeader() const
52 {
53 return object_;
54 }
55
GetFromObjectHeader() const56 ObjectHeader *GCRoot::GetFromObjectHeader() const
57 {
58 ASSERT((from_object_ != nullptr && type_ == RootType::ROOT_TENURED) || type_ != RootType::ROOT_TENURED);
59 return from_object_;
60 }
61
operator <<(std::ostream & os,const GCRoot & root)62 std::ostream &operator<<(std::ostream &os, const GCRoot &root)
63 {
64 switch (root.GetType()) {
65 case RootType::ROOT_CLASS:
66 os << "ROOT CLASS";
67 break;
68 case RootType::ROOT_FRAME:
69 os << "ROOT FRAME";
70 break;
71 case RootType::ROOT_THREAD:
72 os << "ROOT THREAD";
73 break;
74 case RootType::ROOT_TENURED:
75 os << "ROOT TENURED";
76 break;
77 case RootType::ROOT_JNI_GLOBAL:
78 os << "ROOT JNI GLOBAL";
79 break;
80 case RootType::ROOT_JNI_LOCAL:
81 os << "ROOT JNI_LOCAL";
82 break;
83 case RootType::ROOT_AOT_STRING_SLOT:
84 os << "ROOT AOT_STRING_SLOT";
85 break;
86 case RootType::ROOT_UNKNOWN:
87 default:
88 LOG(FATAL, GC) << "ROOT UNKNOWN";
89 break;
90 }
91 os << std::hex << " " << root.GetObjectHeader() << std::endl;
92 return os;
93 }
94
95 template <class LanguageConfig>
VisitNonHeapRoots(const GCRootVisitor & gc_root_visitor,VisitGCRootFlags flags) const96 void RootManager<LanguageConfig>::VisitNonHeapRoots(const GCRootVisitor &gc_root_visitor, VisitGCRootFlags flags) const
97 {
98 VisitLocalRoots(gc_root_visitor);
99 VisitClassRoots(gc_root_visitor, flags);
100 VisitClassLinkerContextRoots(gc_root_visitor);
101 VisitVmRoots(gc_root_visitor);
102 vm_->GetGlobalObjectStorage()->VisitObjects(gc_root_visitor, mem::RootType::ROOT_JNI_GLOBAL);
103 }
104
105 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) const106 void RootManager<LanguageConfig>::VisitCardTableRoots(CardTable *card_table, ObjectAllocatorBase *allocator,
107 GCRootVisitor root_visitor, MemRangeChecker range_checker,
108 ObjectChecker range_object_checker,
109 ObjectChecker from_object_checker, uint32_t processed_flag) const
110 {
111 card_table->VisitMarked(
112 [&allocator, &root_visitor, &range_checker, &range_object_checker, &from_object_checker,
113 &card_table](MemRange mem_range) {
114 if (range_checker(mem_range)) {
115 auto objects_in_range_visitor = [&root_visitor, &range_object_checker,
116 &from_object_checker](ObjectHeader *object_header) {
117 auto traverse_object_in_range = [&root_visitor, &range_object_checker](
118 ObjectHeader *from_object, ObjectHeader *object_to_traverse) {
119 if (range_object_checker(object_to_traverse)) {
120 // The weak references from dynobjects should not be regarded as roots.
121 TaggedValue value(object_to_traverse);
122 if (!value.IsWeak()) {
123 root_visitor(GCRoot(RootType::ROOT_TENURED, from_object, object_to_traverse));
124 }
125 }
126 };
127 if (from_object_checker(object_header)) {
128 ObjectHelpers<LanguageConfig::LANG_TYPE>::TraverseAllObjects(object_header,
129 traverse_object_in_range);
130 }
131 };
132 allocator->IterateOverObjectsInRange(mem_range, objects_in_range_visitor);
133 } else {
134 card_table->MarkCard(mem_range.GetStartAddress());
135 }
136 },
137 processed_flag);
138 }
139
140 template <class LanguageConfig>
VisitRootsForThread(ManagedThread * thread,const GCRootVisitor & gc_root_visitor) const141 void RootManager<LanguageConfig>::VisitRootsForThread(ManagedThread *thread, const GCRootVisitor &gc_root_visitor) const
142 {
143 LOG(DEBUG, GC) << "Start collecting roots for thread " << thread->GetId();
144
145 thread->VisitGCRoots([&gc_root_visitor](ObjectHeader *obj) {
146 LOG(DEBUG, GC) << " Found root for thread" << GetDebugInfoAboutObject(obj);
147 gc_root_visitor({RootType::ROOT_THREAD, obj});
148 });
149 LOG(DEBUG, GC) << "Finish collecting roots for thread " << thread->GetId();
150 }
151
152 template <class LanguageConfig>
VisitLocalRoots(const GCRootVisitor & gc_root_visitor) const153 void RootManager<LanguageConfig>::VisitLocalRoots(const GCRootVisitor &gc_root_visitor) const
154 {
155 auto thread_visitor = [this, &gc_root_visitor](ManagedThread *thread) {
156 VisitRootsForThread(thread, gc_root_visitor);
157 for (StackWalker stack(thread); stack.HasFrame(); stack.NextFrame()) {
158 LOG(DEBUG, GC) << " VisitRoots frame " << std::hex << stack.GetFp();
159 stack.IterateObjects([this, &gc_root_visitor](auto &vreg) {
160 VisitRegisterRoot(vreg, gc_root_visitor);
161 return true;
162 });
163 }
164 return true;
165 };
166 if constexpr (LanguageConfig::MT_MODE == MT_MODE_MULTI) { // NOLINT
167 vm_->GetThreadManager()->EnumerateThreads(thread_visitor, static_cast<unsigned int>(EnumerationFlag::ALL));
168 } else { // NOLINT
169 thread_visitor(ManagedThread::GetCurrent());
170 }
171 }
172
173 template <class LanguageConfig>
VisitRegisterRoot(const Frame::VRegister & v_register,const GCRootVisitor & gc_root_visitor) const174 void RootManager<LanguageConfig>::VisitRegisterRoot(const Frame::VRegister &v_register,
175 const GCRootVisitor &gc_root_visitor) const
176 {
177 if (UNLIKELY(v_register.HasObject())) {
178 ObjectHeader *object_header = v_register.GetReference();
179 if (object_header != nullptr) {
180 LOG(DEBUG, GC) << " Found root for register" << GetDebugInfoAboutObject(object_header);
181 gc_root_visitor({RootType::ROOT_FRAME, object_header});
182 }
183 }
184 }
185
186 template <class LanguageConfig>
VisitVmRoots(const GCRootVisitor & gc_root_visitor) const187 void RootManager<LanguageConfig>::VisitVmRoots(const GCRootVisitor &gc_root_visitor) const
188 {
189 vm_->VisitVmRoots(gc_root_visitor);
190 }
191
192 template <class LanguageConfig>
UpdateVmRefs()193 void RootManager<LanguageConfig>::UpdateVmRefs()
194 {
195 vm_->UpdateVmRefs();
196 }
197
198 template <class LanguageConfig>
UpdateGlobalObjectStorage()199 void RootManager<LanguageConfig>::UpdateGlobalObjectStorage()
200 {
201 vm_->GetGlobalObjectStorage()->UpdateMovedRefs();
202 }
203
204 template <class LanguageConfig>
VisitClassRoots(const GCRootVisitor & gc_root_visitor,VisitGCRootFlags flags) const205 void RootManager<LanguageConfig>::VisitClassRoots(const GCRootVisitor &gc_root_visitor, VisitGCRootFlags flags) const
206 {
207 if constexpr (LanguageConfig::LANG_TYPE == LANG_TYPE_DYNAMIC) { // NOLINT
208 // Dynamic languages have not class roots
209 return;
210 }
211
212 LOG(DEBUG, GC) << "Start collecting roots for classes";
213 auto class_linker = Runtime::GetCurrent()->GetClassLinker();
214 auto class_root_visitor = [&gc_root_visitor](Class *cls) {
215 gc_root_visitor({RootType::ROOT_CLASS, cls->GetManagedObject()});
216 LOG(DEBUG, GC) << " Found class root " << GetDebugInfoAboutObject(cls->GetManagedObject());
217 return true;
218 };
219 auto *extension = class_linker->GetExtension(LanguageConfig::LANG);
220 extension->EnumerateClasses(class_root_visitor, flags);
221 LOG(DEBUG, GC) << "Finish collecting roots for classes";
222 }
223
224 template <class LanguageConfig>
UpdateThreadLocals()225 void RootManager<LanguageConfig>::UpdateThreadLocals()
226 {
227 LOG(DEBUG, GC) << "=== ThreadLocals Update moved. BEGIN ===";
228 if constexpr (LanguageConfig::MT_MODE == MT_MODE_MULTI) { // NOLINT
229 vm_->GetThreadManager()->EnumerateThreads(
230 [](MTManagedThread *thread) {
231 thread->UpdateGCRoots();
232 return true;
233 },
234 static_cast<unsigned int>(EnumerationFlag::ALL));
235 } else { // NOLINT
236 vm_->GetAssociatedThread()->UpdateGCRoots();
237 }
238 LOG(DEBUG, GC) << "=== ThreadLocals Update moved. END ===";
239 }
240
241 template <class LanguageConfig>
VisitClassLinkerContextRoots(const GCRootVisitor & gc_root_visitor) const242 void RootManager<LanguageConfig>::VisitClassLinkerContextRoots(const GCRootVisitor &gc_root_visitor) const
243 {
244 LOG(DEBUG, GC) << "Start collecting roots for class linker contexts";
245 auto class_linker = Runtime::GetCurrent()->GetClassLinker();
246 auto *extension = class_linker->GetExtension(LanguageConfig::LANG);
247 extension->EnumerateContexts([&gc_root_visitor](ClassLinkerContext *ctx) {
248 ctx->VisitGCRoots([&gc_root_visitor](ObjectHeader *obj) {
249 LOG(DEBUG, GC) << " Found root for class linker context " << GetDebugInfoAboutObject(obj);
250 gc_root_visitor({RootType::ROOT_CLASS_LINKER, obj});
251 });
252 return true;
253 });
254 LOG(DEBUG, GC) << "Finish collecting roots for class linker contexts";
255 }
256
257 template <class LanguageConfig>
UpdateClassLinkerContextRoots()258 void RootManager<LanguageConfig>::UpdateClassLinkerContextRoots()
259 {
260 auto class_linker = Runtime::GetCurrent()->GetClassLinker();
261 auto *extension = class_linker->GetExtension(LanguageConfig::LANG);
262 extension->EnumerateContexts([](ClassLinkerContext *ctx) {
263 ctx->UpdateGCRoots();
264 return true;
265 });
266 }
267
operator &(VisitGCRootFlags left,VisitGCRootFlags right)268 uint32_t operator&(VisitGCRootFlags left, VisitGCRootFlags right)
269 {
270 return static_cast<uint32_t>(left) & static_cast<uint32_t>(right);
271 }
272
operator |(VisitGCRootFlags left,VisitGCRootFlags right)273 VisitGCRootFlags operator|(VisitGCRootFlags left, VisitGCRootFlags right)
274 {
275 return static_cast<VisitGCRootFlags>(static_cast<uint32_t>(left) | static_cast<uint32_t>(right));
276 }
277
278 template class RootManager<PandaAssemblyLanguageConfig>;
279
280 } // namespace panda::mem
281