• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_CLASS_LINKER_INL_H_
18 #define ART_RUNTIME_CLASS_LINKER_INL_H_
19 
20 #include <atomic>
21 
22 #include "android-base/thread_annotations.h"
23 #include "art_field-inl.h"
24 #include "art_method-inl.h"
25 #include "base/mutex.h"
26 #include "class_linker.h"
27 #include "dex/dex_file.h"
28 #include "dex/dex_file_structs.h"
29 #include "gc_root-inl.h"
30 #include "handle_scope-inl.h"
31 #include "jni/jni_internal.h"
32 #include "mirror/class_loader.h"
33 #include "mirror/dex_cache-inl.h"
34 #include "mirror/iftable.h"
35 #include "mirror/object_array-inl.h"
36 #include "obj_ptr-inl.h"
37 #include "scoped_thread_state_change-inl.h"
38 #include "well_known_classes.h"
39 
40 namespace art {
41 
FindArrayClass(Thread * self,ObjPtr<mirror::Class> element_class)42 inline ObjPtr<mirror::Class> ClassLinker::FindArrayClass(Thread* self,
43                                                          ObjPtr<mirror::Class> element_class) {
44   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
45     // Read the cached array class once to avoid races with other threads setting it.
46     ObjPtr<mirror::Class> array_class = find_array_class_cache_[i].Read();
47     if (array_class != nullptr && array_class->GetComponentType() == element_class) {
48       return array_class;
49     }
50   }
51   std::string descriptor = "[";
52   std::string temp;
53   descriptor += element_class->GetDescriptor(&temp);
54   StackHandleScope<1> hs(Thread::Current());
55   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(element_class->GetClassLoader()));
56   ObjPtr<mirror::Class> array_class = FindClass(self, descriptor.c_str(), class_loader);
57   if (array_class != nullptr) {
58     // Benign races in storing array class and incrementing index.
59     size_t victim_index = find_array_class_cache_next_victim_;
60     find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
61     find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
62   } else {
63     // We should have a NoClassDefFoundError.
64     self->AssertPendingException();
65   }
66   return array_class;
67 }
68 
ResolveString(dex::StringIndex string_idx,ArtField * referrer)69 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
70                                                          ArtField* referrer) {
71   Thread::PoisonObjectPointersIfDebug();
72   DCHECK(!Thread::Current()->IsExceptionPending());
73   // We do not need the read barrier for getting the DexCache for the initial resolved type
74   // lookup as both from-space and to-space copies point to the same native resolved types array.
75   ObjPtr<mirror::String> resolved =
76       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
77   if (resolved == nullptr) {
78     resolved = DoResolveString(string_idx, referrer->GetDexCache());
79   }
80   return resolved;
81 }
82 
ResolveString(dex::StringIndex string_idx,ArtMethod * referrer)83 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
84                                                          ArtMethod* referrer) {
85   Thread::PoisonObjectPointersIfDebug();
86   DCHECK(!Thread::Current()->IsExceptionPending());
87   // We do not need the read barrier for getting the DexCache for the initial resolved type
88   // lookup as both from-space and to-space copies point to the same native resolved types array.
89   ObjPtr<mirror::String> resolved =
90       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
91   if (resolved == nullptr) {
92     resolved = DoResolveString(string_idx, referrer->GetDexCache());
93   }
94   return resolved;
95 }
96 
ResolveString(dex::StringIndex string_idx,Handle<mirror::DexCache> dex_cache)97 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
98                                                          Handle<mirror::DexCache> dex_cache) {
99   Thread::PoisonObjectPointersIfDebug();
100   DCHECK(!Thread::Current()->IsExceptionPending());
101   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
102   if (resolved == nullptr) {
103     resolved = DoResolveString(string_idx, dex_cache);
104   }
105   return resolved;
106 }
107 
LookupString(dex::StringIndex string_idx,ObjPtr<mirror::DexCache> dex_cache)108 inline ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
109                                                         ObjPtr<mirror::DexCache> dex_cache) {
110   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
111   if (resolved == nullptr) {
112     resolved = DoLookupString(string_idx, dex_cache);
113   }
114   return resolved;
115 }
116 
ResolveType(dex::TypeIndex type_idx,ObjPtr<mirror::Class> referrer)117 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
118                                                       ObjPtr<mirror::Class> referrer) {
119   if (kObjPtrPoisoning) {
120     StackHandleScope<1> hs(Thread::Current());
121     HandleWrapperObjPtr<mirror::Class> referrer_wrapper = hs.NewHandleWrapper(&referrer);
122     Thread::Current()->PoisonObjectPointers();
123   }
124   DCHECK(!Thread::Current()->IsExceptionPending());
125   // We do not need the read barrier for getting the DexCache for the initial resolved type
126   // lookup as both from-space and to-space copies point to the same native resolved types array.
127   ObjPtr<mirror::Class> resolved_type =
128       referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
129   if (resolved_type == nullptr) {
130     resolved_type = DoResolveType(type_idx, referrer);
131   }
132   return resolved_type;
133 }
134 
ResolveType(dex::TypeIndex type_idx,ArtField * referrer)135 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
136                                                       ArtField* referrer) {
137   Thread::PoisonObjectPointersIfDebug();
138   DCHECK(!Thread::Current()->IsExceptionPending());
139   // We do not need the read barrier for getting the DexCache for the initial resolved type
140   // lookup as both from-space and to-space copies point to the same native resolved types array.
141   ObjPtr<mirror::Class> resolved_type =
142       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
143   if (UNLIKELY(resolved_type == nullptr)) {
144     resolved_type = DoResolveType(type_idx, referrer);
145   }
146   return resolved_type;
147 }
148 
ResolveType(dex::TypeIndex type_idx,ArtMethod * referrer)149 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
150                                                       ArtMethod* referrer) {
151   Thread::PoisonObjectPointersIfDebug();
152   DCHECK(!Thread::Current()->IsExceptionPending());
153   // We do not need the read barrier for getting the DexCache for the initial resolved type
154   // lookup as both from-space and to-space copies point to the same native resolved types array.
155   ObjPtr<mirror::Class> resolved_type =
156       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
157   if (UNLIKELY(resolved_type == nullptr)) {
158     resolved_type = DoResolveType(type_idx, referrer);
159   }
160   return resolved_type;
161 }
162 
ResolveType(dex::TypeIndex type_idx,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader)163 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
164                                                       Handle<mirror::DexCache> dex_cache,
165                                                       Handle<mirror::ClassLoader> class_loader) {
166   DCHECK(dex_cache != nullptr);
167   Thread::PoisonObjectPointersIfDebug();
168   ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
169   if (resolved == nullptr) {
170     resolved = DoResolveType(type_idx, dex_cache, class_loader);
171   }
172   return resolved;
173 }
174 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::Class> referrer)175 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
176                                                              ObjPtr<mirror::Class> referrer) {
177   // We do not need the read barrier for getting the DexCache for the initial resolved type
178   // lookup as both from-space and to-space copies point to the same native resolved types array.
179   ObjPtr<mirror::Class> type =
180       referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
181   if (type == nullptr) {
182     type = DoLookupResolvedType(type_idx, referrer);
183   }
184   return type;
185 }
186 
LookupResolvedType(dex::TypeIndex type_idx,ArtField * referrer)187 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
188                                                              ArtField* referrer) {
189   // We do not need the read barrier for getting the DexCache for the initial resolved type
190   // lookup as both from-space and to-space copies point to the same native resolved types array.
191   ObjPtr<mirror::Class> type =
192       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
193   if (type == nullptr) {
194     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
195   }
196   return type;
197 }
198 
LookupResolvedType(dex::TypeIndex type_idx,ArtMethod * referrer)199 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
200                                                              ArtMethod* referrer) {
201   // We do not need the read barrier for getting the DexCache for the initial resolved type
202   // lookup as both from-space and to-space copies point to the same native resolved types array.
203   ObjPtr<mirror::Class> type =
204       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
205   if (type == nullptr) {
206     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
207   }
208   return type;
209 }
210 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)211 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
212     dex::TypeIndex type_idx,
213     ObjPtr<mirror::DexCache> dex_cache,
214     ObjPtr<mirror::ClassLoader> class_loader) {
215   ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
216   if (type == nullptr) {
217     type = DoLookupResolvedType(type_idx, dex_cache, class_loader);
218   }
219   return type;
220 }
221 
222 template <bool kThrowOnError, typename ClassGetter>
CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,InvokeType type,ClassGetter class_getter)223 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
224                                                   InvokeType type,
225                                                   ClassGetter class_getter) {
226   switch (type) {
227     case kStatic:
228     case kSuper:
229     case kPolymorphic:
230       break;
231     case kInterface: {
232       // We have to check whether the method id really belongs to an interface (dex static bytecode
233       // constraints A15, A16). Otherwise you must not invoke-interface on it.
234       ObjPtr<mirror::Class> klass = class_getter();
235       if (UNLIKELY(!klass->IsInterface())) {
236         if (kThrowOnError) {
237           ThrowIncompatibleClassChangeError(klass,
238                                             "Found class %s, but interface was expected",
239                                             klass->PrettyDescriptor().c_str());
240         }
241         return true;
242       }
243       break;
244     }
245     case kDirect:
246       if (dex_cache->GetDexFile()->SupportsDefaultMethods()) {
247         break;
248       }
249       FALLTHROUGH_INTENDED;
250     case kVirtual: {
251       // Similarly, invoke-virtual (and invoke-direct without default methods) must reference
252       // a non-interface class (dex static bytecode constraint A24, A25).
253       ObjPtr<mirror::Class> klass = class_getter();
254       if (UNLIKELY(klass->IsInterface())) {
255         if (kThrowOnError) {
256           ThrowIncompatibleClassChangeError(klass,
257                                             "Found interface %s, but class was expected",
258                                             klass->PrettyDescriptor().c_str());
259         }
260         return true;
261       }
262       break;
263     }
264     default:
265       LOG(FATAL) << "Unreachable - invocation type: " << type;
266       UNREACHABLE();
267   }
268   return false;
269 }
270 
271 template <bool kThrow>
CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,InvokeType type,uint32_t method_idx,ObjPtr<mirror::ClassLoader> class_loader)272 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
273                                                   InvokeType type,
274                                                   uint32_t method_idx,
275                                                   ObjPtr<mirror::ClassLoader> class_loader) {
276   return CheckInvokeClassMismatch<kThrow>(
277       dex_cache,
278       type,
279       [this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
280         const dex::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
281         ObjPtr<mirror::Class> klass =
282             LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
283         DCHECK(klass != nullptr) << dex_cache->GetDexFile()->PrettyMethod(method_idx);
284         return klass;
285       });
286 }
287 
LookupResolvedMethod(uint32_t method_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)288 inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
289                                                     ObjPtr<mirror::DexCache> dex_cache,
290                                                     ObjPtr<mirror::ClassLoader> class_loader) {
291   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
292   if (resolved == nullptr) {
293     const DexFile& dex_file = *dex_cache->GetDexFile();
294     const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
295     ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
296     if (klass != nullptr) {
297       resolved = FindResolvedMethod(klass, dex_cache, class_loader, method_idx);
298     }
299   }
300   return resolved;
301 }
302 
303 template <InvokeType type, ClassLinker::ResolveMode kResolveMode>
GetResolvedMethod(uint32_t method_idx,ArtMethod * referrer)304 inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) {
305   DCHECK(referrer != nullptr);
306   // Note: The referrer can be a Proxy constructor. In that case, we need to do the
307   // lookup in the context of the original method from where it steals the code.
308   // However, we delay the GetInterfaceMethodIfProxy() until needed.
309   DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
310   // We do not need the read barrier for getting the DexCache for the initial resolved method
311   // lookup as both from-space and to-space copies point to the same native resolved methods array.
312   ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
313       method_idx);
314   if (resolved_method == nullptr) {
315     return nullptr;
316   }
317   DCHECK(!resolved_method->IsRuntimeMethod());
318   if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
319     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
320     // Check if the invoke type matches the class type.
321     ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
322     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetClassLoader();
323     const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
324     ObjPtr<mirror::Class> cls = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
325     if (cls == nullptr) {
326       // The verifier breaks the invariant that a resolved method must have its
327       // class in the class table. Because this method should only lookup and not
328       // resolve class, return null. The caller is responsible for calling
329       // `ResolveMethod` afterwards.
330       // b/73760543
331       return nullptr;
332     }
333     if (CheckInvokeClassMismatch</* kThrow= */ false>(dex_cache, type, method_idx, class_loader)) {
334       return nullptr;
335     }
336     // Check access.
337     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
338     if (!referring_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
339                                                   resolved_method,
340                                                   dex_cache,
341                                                   method_idx)) {
342       return nullptr;
343     }
344     // Check if the invoke type matches the method type.
345     if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
346       return nullptr;
347     }
348   }
349   return resolved_method;
350 }
351 
352 template <ClassLinker::ResolveMode kResolveMode>
ResolveMethod(Thread * self,uint32_t method_idx,ArtMethod * referrer,InvokeType type)353 inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
354                                              uint32_t method_idx,
355                                              ArtMethod* referrer,
356                                              InvokeType type) {
357   DCHECK(referrer != nullptr);
358   // Note: The referrer can be a Proxy constructor. In that case, we need to do the
359   // lookup in the context of the original method from where it steals the code.
360   // However, we delay the GetInterfaceMethodIfProxy() until needed.
361   DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
362   Thread::PoisonObjectPointersIfDebug();
363   // We do not need the read barrier for getting the DexCache for the initial resolved method
364   // lookup as both from-space and to-space copies point to the same native resolved methods array.
365   ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
366       method_idx);
367   DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod());
368   if (UNLIKELY(resolved_method == nullptr)) {
369     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
370     ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
371     StackHandleScope<2> hs(self);
372     Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
373     Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
374     resolved_method = ResolveMethod<kResolveMode>(method_idx,
375                                                   h_dex_cache,
376                                                   h_class_loader,
377                                                   referrer,
378                                                   type);
379   } else if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
380     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
381     const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
382     ObjPtr<mirror::Class> cls =
383         LookupResolvedType(method_id.class_idx_,
384                            referrer->GetDexCache(),
385                            referrer->GetClassLoader());
386     if (cls == nullptr) {
387       // The verifier breaks the invariant that a resolved method must have its
388       // class in the class table, so resolve the type in case we haven't found it.
389       // b/73760543
390       StackHandleScope<2> hs(Thread::Current());
391       Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
392       Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(referrer->GetClassLoader()));
393       cls = ResolveType(method_id.class_idx_, h_dex_cache, h_class_loader);
394       if (hs.Self()->IsExceptionPending()) {
395         return nullptr;
396       }
397     }
398     // Check if the invoke type matches the class type.
399     if (CheckInvokeClassMismatch</* kThrow= */ true>(
400             referrer->GetDexCache(), type, [cls]() { return cls; })) {
401       DCHECK(Thread::Current()->IsExceptionPending());
402       return nullptr;
403     }
404     // Check access.
405     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
406     if (!referring_class->CheckResolvedMethodAccess(resolved_method->GetDeclaringClass(),
407                                                     resolved_method,
408                                                     referrer->GetDexCache(),
409                                                     method_idx,
410                                                     type)) {
411       DCHECK(Thread::Current()->IsExceptionPending());
412       return nullptr;
413     }
414     // Check if the invoke type matches the method type.
415     if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
416       ThrowIncompatibleClassChangeError(type,
417                                         resolved_method->GetInvokeType(),
418                                         resolved_method,
419                                         referrer);
420       return nullptr;
421     }
422   }
423   // Note: We cannot check here to see whether we added the method to the cache. It
424   //       might be an erroneous class, which results in it being hidden from us.
425   return resolved_method;
426 }
427 
LookupResolvedField(uint32_t field_idx,ArtMethod * referrer,bool is_static)428 inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
429                                                   ArtMethod* referrer,
430                                                   bool is_static) {
431   // We do not need the read barrier for getting the DexCache for the initial resolved field
432   // lookup as both from-space and to-space copies point to the same native resolved fields array.
433   ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
434       field_idx);
435   if (field == nullptr) {
436     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader();
437     field = LookupResolvedField(field_idx, referrer->GetDexCache(), class_loader, is_static);
438   }
439   return field;
440 }
441 
ResolveField(uint32_t field_idx,ArtMethod * referrer,bool is_static)442 inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
443                                            ArtMethod* referrer,
444                                            bool is_static) {
445   Thread::PoisonObjectPointersIfDebug();
446   // We do not need the read barrier for getting the DexCache for the initial resolved field
447   // lookup as both from-space and to-space copies point to the same native resolved fields array.
448   ArtField* resolved_field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
449       field_idx);
450   if (UNLIKELY(resolved_field == nullptr)) {
451     StackHandleScope<2> hs(Thread::Current());
452     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
453     Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
454     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
455     resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static);
456     // Note: We cannot check here to see whether we added the field to the cache. The type
457     //       might be an erroneous class, which results in it being hidden from us.
458   }
459   return resolved_field;
460 }
461 
462 template <class Visitor>
VisitClassTables(const Visitor & visitor)463 inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
464   Thread* const self = Thread::Current();
465   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
466   for (const ClassLoaderData& data : class_loaders_) {
467     if (data.class_table != nullptr) {
468       visitor(data.class_table);
469     }
470   }
471 }
472 
473 template <ReadBarrierOption kReadBarrierOption>
GetClassRoots()474 inline ObjPtr<mirror::ObjectArray<mirror::Class>> ClassLinker::GetClassRoots() {
475   ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
476       class_roots_.Read<kReadBarrierOption>();
477   DCHECK(class_roots != nullptr);
478   return class_roots;
479 }
480 
481 template <typename Visitor>
VisitKnownDexFiles(Thread * self,Visitor visitor)482 void ClassLinker::VisitKnownDexFiles(Thread* self, Visitor visitor) {
483   ReaderMutexLock rmu(self, *Locks::dex_lock_);
484   std::for_each(dex_caches_.begin(),
485                 dex_caches_.end(),
486                 [&](DexCacheData& dcd) REQUIRES(Locks::mutator_lock_) {
487                   if (dcd.IsValid()) {
488                     visitor(dcd.dex_file);
489                   }
490                 });
491 }
492 
493 }  // namespace art
494 
495 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
496