• 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 "class_table-inl.h"
28 #include "dex/dex_file.h"
29 #include "dex/dex_file_structs.h"
30 #include "gc_root-inl.h"
31 #include "handle_scope-inl.h"
32 #include "jni/jni_internal.h"
33 #include "mirror/class_loader.h"
34 #include "mirror/dex_cache-inl.h"
35 #include "mirror/iftable.h"
36 #include "mirror/object_array-inl.h"
37 #include "obj_ptr-inl.h"
38 #include "scoped_thread_state_change-inl.h"
39 #include "well_known_classes.h"
40 
41 namespace art {
42 
FindArrayClass(Thread * self,ObjPtr<mirror::Class> element_class)43 inline ObjPtr<mirror::Class> ClassLinker::FindArrayClass(Thread* self,
44                                                          ObjPtr<mirror::Class> element_class) {
45   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
46     // Read the cached array class once to avoid races with other threads setting it.
47     ObjPtr<mirror::Class> array_class = find_array_class_cache_[i].Read();
48     if (array_class != nullptr && array_class->GetComponentType() == element_class) {
49       return array_class;
50     }
51   }
52   std::string descriptor = "[";
53   std::string temp;
54   descriptor += element_class->GetDescriptor(&temp);
55   StackHandleScope<1> hs(Thread::Current());
56   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(element_class->GetClassLoader()));
57   ObjPtr<mirror::Class> array_class = FindClass(self, descriptor.c_str(), class_loader);
58   if (array_class != nullptr) {
59     // Benign races in storing array class and incrementing index.
60     size_t victim_index = find_array_class_cache_next_victim_;
61     find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
62     find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
63   } else {
64     // We should have a NoClassDefFoundError.
65     self->AssertPendingException();
66   }
67   return array_class;
68 }
69 
ResolveString(dex::StringIndex string_idx,ArtField * referrer)70 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
71                                                          ArtField* referrer) {
72   Thread::PoisonObjectPointersIfDebug();
73   DCHECK(!Thread::Current()->IsExceptionPending());
74   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
75   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
76   if (resolved == nullptr) {
77     resolved = DoResolveString(string_idx, dex_cache);
78   }
79   return resolved;
80 }
81 
ResolveString(dex::StringIndex string_idx,ArtMethod * referrer)82 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
83                                                          ArtMethod* referrer) {
84   Thread::PoisonObjectPointersIfDebug();
85   DCHECK(!Thread::Current()->IsExceptionPending());
86   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
87   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
88   if (resolved == nullptr) {
89     resolved = DoResolveString(string_idx, dex_cache);
90   }
91   return resolved;
92 }
93 
ResolveString(dex::StringIndex string_idx,Handle<mirror::DexCache> dex_cache)94 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
95                                                          Handle<mirror::DexCache> dex_cache) {
96   Thread::PoisonObjectPointersIfDebug();
97   DCHECK(!Thread::Current()->IsExceptionPending());
98   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
99   if (resolved == nullptr) {
100     resolved = DoResolveString(string_idx, dex_cache);
101   }
102   return resolved;
103 }
104 
LookupString(dex::StringIndex string_idx,ObjPtr<mirror::DexCache> dex_cache)105 inline ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
106                                                         ObjPtr<mirror::DexCache> dex_cache) {
107   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
108   if (resolved == nullptr) {
109     resolved = DoLookupString(string_idx, dex_cache);
110   }
111   return resolved;
112 }
113 
ResolveType(dex::TypeIndex type_idx,ObjPtr<mirror::Class> referrer)114 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
115                                                       ObjPtr<mirror::Class> referrer) {
116   if (kObjPtrPoisoning) {
117     StackHandleScope<1> hs(Thread::Current());
118     HandleWrapperObjPtr<mirror::Class> referrer_wrapper = hs.NewHandleWrapper(&referrer);
119     Thread::Current()->PoisonObjectPointers();
120   }
121   DCHECK(!Thread::Current()->IsExceptionPending());
122   ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
123   if (resolved_type == nullptr) {
124     resolved_type = DoResolveType(type_idx, referrer);
125   }
126   return resolved_type;
127 }
128 
ResolveType(dex::TypeIndex type_idx,ArtField * referrer)129 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
130                                                       ArtField* referrer) {
131   Thread::PoisonObjectPointersIfDebug();
132   DCHECK(!Thread::Current()->IsExceptionPending());
133   ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
134   if (UNLIKELY(resolved_type == nullptr)) {
135     resolved_type = DoResolveType(type_idx, referrer);
136   }
137   return resolved_type;
138 }
139 
ResolveType(dex::TypeIndex type_idx,ArtMethod * referrer)140 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
141                                                       ArtMethod* referrer) {
142   Thread::PoisonObjectPointersIfDebug();
143   DCHECK(!Thread::Current()->IsExceptionPending());
144   ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
145   if (UNLIKELY(resolved_type == nullptr)) {
146     resolved_type = DoResolveType(type_idx, referrer);
147   }
148   return resolved_type;
149 }
150 
ResolveType(dex::TypeIndex type_idx,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader)151 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
152                                                       Handle<mirror::DexCache> dex_cache,
153                                                       Handle<mirror::ClassLoader> class_loader) {
154   DCHECK(dex_cache != nullptr);
155   DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
156   Thread::PoisonObjectPointersIfDebug();
157   ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
158   if (resolved == nullptr) {
159     resolved = DoResolveType(type_idx, dex_cache, class_loader);
160   }
161   return resolved;
162 }
163 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::Class> referrer)164 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
165                                                              ObjPtr<mirror::Class> referrer) {
166   ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx);
167   if (type == nullptr) {
168     type = DoLookupResolvedType(type_idx, referrer);
169   }
170   return type;
171 }
172 
LookupResolvedType(dex::TypeIndex type_idx,ArtField * referrer)173 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
174                                                              ArtField* referrer) {
175   // We do not need the read barrier for getting the DexCache for the initial resolved type
176   // lookup as both from-space and to-space copies point to the same native resolved types array.
177   ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx);
178   if (type == nullptr) {
179     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
180   }
181   return type;
182 }
183 
LookupResolvedType(dex::TypeIndex type_idx,ArtMethod * referrer)184 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
185                                                              ArtMethod* referrer) {
186   // We do not need the read barrier for getting the DexCache for the initial resolved type
187   // lookup as both from-space and to-space copies point to the same native resolved types array.
188   ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx);
189   if (type == nullptr) {
190     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
191   }
192   return type;
193 }
194 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)195 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
196     dex::TypeIndex type_idx,
197     ObjPtr<mirror::DexCache> dex_cache,
198     ObjPtr<mirror::ClassLoader> class_loader) {
199   DCHECK(dex_cache->GetClassLoader() == class_loader);
200   ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
201   if (type == nullptr) {
202     type = DoLookupResolvedType(type_idx, dex_cache, class_loader);
203   }
204   return type;
205 }
206 
207 template <bool kThrowOnError, typename ClassGetter>
CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,InvokeType type,ClassGetter class_getter)208 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
209                                                   InvokeType type,
210                                                   ClassGetter class_getter) {
211   switch (type) {
212     case kStatic:
213     case kSuper:
214     case kPolymorphic:
215       break;
216     case kInterface: {
217       // We have to check whether the method id really belongs to an interface (dex static bytecode
218       // constraints A15, A16). Otherwise you must not invoke-interface on it.
219       ObjPtr<mirror::Class> klass = class_getter();
220       if (UNLIKELY(!klass->IsInterface())) {
221         if (kThrowOnError) {
222           ThrowIncompatibleClassChangeError(klass,
223                                             "Found class %s, but interface was expected",
224                                             klass->PrettyDescriptor().c_str());
225         }
226         return true;
227       }
228       break;
229     }
230     case kDirect:
231       if (dex_cache->GetDexFile()->SupportsDefaultMethods()) {
232         break;
233       }
234       FALLTHROUGH_INTENDED;
235     case kVirtual: {
236       // Similarly, invoke-virtual (and invoke-direct without default methods) must reference
237       // a non-interface class (dex static bytecode constraint A24, A25).
238       ObjPtr<mirror::Class> klass = class_getter();
239       if (UNLIKELY(klass->IsInterface())) {
240         if (kThrowOnError) {
241           ThrowIncompatibleClassChangeError(klass,
242                                             "Found interface %s, but class was expected",
243                                             klass->PrettyDescriptor().c_str());
244         }
245         return true;
246       }
247       break;
248     }
249     default:
250       LOG(FATAL) << "Unreachable - invocation type: " << type;
251       UNREACHABLE();
252   }
253   return false;
254 }
255 
256 template <bool kThrow>
CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,InvokeType type,uint32_t method_idx,ObjPtr<mirror::ClassLoader> class_loader)257 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
258                                                   InvokeType type,
259                                                   uint32_t method_idx,
260                                                   ObjPtr<mirror::ClassLoader> class_loader) {
261   DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr());
262   return CheckInvokeClassMismatch<kThrow>(
263       dex_cache,
264       type,
265       [this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
266         const dex::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
267         ObjPtr<mirror::Class> klass =
268             LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
269         DCHECK(klass != nullptr) << dex_cache->GetDexFile()->PrettyMethod(method_idx);
270         return klass;
271       });
272 }
273 
LookupResolvedMethod(uint32_t method_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)274 inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
275                                                     ObjPtr<mirror::DexCache> dex_cache,
276                                                     ObjPtr<mirror::ClassLoader> class_loader) {
277   DCHECK(dex_cache->GetClassLoader() == class_loader);
278   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
279   if (resolved == nullptr) {
280     const DexFile& dex_file = *dex_cache->GetDexFile();
281     const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
282     ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
283     if (klass != nullptr) {
284       resolved = FindResolvedMethod(klass, dex_cache, class_loader, method_idx);
285     }
286   }
287   return resolved;
288 }
289 
290 template <ClassLinker::ResolveMode kResolveMode>
ResolveMethod(Thread * self,uint32_t method_idx,ArtMethod * referrer,InvokeType type)291 inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
292                                              uint32_t method_idx,
293                                              ArtMethod* referrer,
294                                              InvokeType type) {
295   DCHECK(referrer != nullptr);
296   DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor());
297 
298   Thread::PoisonObjectPointersIfDebug();
299   // Fast path: no checks and in the dex cache.
300   if (kResolveMode == ResolveMode::kNoChecks) {
301     ArtMethod* resolved_method = referrer->GetDexCache()->GetResolvedMethod(method_idx);
302     if (resolved_method != nullptr) {
303       DCHECK(!resolved_method->IsRuntimeMethod());
304       return resolved_method;
305     }
306   }
307 
308   // For a Proxy constructor, we need to do the lookup in the context of the original method
309   // from where it steals the code.
310   referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
311   StackHandleScope<2> hs(self);
312   Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
313   Handle<mirror::ClassLoader> class_loader(
314       hs.NewHandle(referrer->GetDeclaringClass()->GetClassLoader()));
315   return ResolveMethod<kResolveMode>(method_idx, dex_cache, class_loader, referrer, type);
316 }
317 
318 template <ClassLinker::ResolveMode kResolveMode>
ResolveMethod(uint32_t method_idx,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader,ArtMethod * referrer,InvokeType type)319 inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
320                                              Handle<mirror::DexCache> dex_cache,
321                                              Handle<mirror::ClassLoader> class_loader,
322                                              ArtMethod* referrer,
323                                              InvokeType type) {
324   DCHECK(dex_cache != nullptr);
325   DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
326   DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
327   DCHECK(referrer == nullptr || !referrer->IsProxyMethod());
328 
329   // Check for hit in the dex cache.
330   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
331   Thread::PoisonObjectPointersIfDebug();
332   DCHECK(resolved == nullptr || !resolved->IsRuntimeMethod());
333   bool valid_dex_cache_method = resolved != nullptr;
334   if (kResolveMode == ResolveMode::kNoChecks && valid_dex_cache_method) {
335     // We have a valid method from the DexCache and no checks to perform.
336     DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
337     return resolved;
338   }
339   const DexFile& dex_file = *dex_cache->GetDexFile();
340   const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
341   ObjPtr<mirror::Class> klass = nullptr;
342   if (valid_dex_cache_method) {
343     // We have a valid method from the DexCache but we need to perform ICCE and IAE checks.
344     DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
345     klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get());
346     if (UNLIKELY(klass == nullptr)) {
347       // We normaly should not end up here. However the verifier currently doesn't guarantee
348       // the invariant of having the klass in the class table. b/73760543
349       klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
350       if (klass == nullptr) {
351         // This can only happen if the current thread is not allowed to load
352         // classes.
353         DCHECK(!Thread::Current()->CanLoadClasses());
354         DCHECK(Thread::Current()->IsExceptionPending());
355         return nullptr;
356       }
357     }
358   } else {
359     // The method was not in the DexCache, resolve the declaring class.
360     klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
361     if (klass == nullptr) {
362       DCHECK(Thread::Current()->IsExceptionPending());
363       return nullptr;
364     }
365     // Look for the method again in case the type resolution updated the cache.
366     resolved = dex_cache->GetResolvedMethod(method_idx);
367     if (kResolveMode == ResolveMode::kNoChecks && resolved != nullptr) {
368       return resolved;
369     }
370   }
371 
372   // Check if the invoke type matches the class type.
373   if (kResolveMode == ResolveMode::kCheckICCEAndIAE &&
374       CheckInvokeClassMismatch</* kThrow= */ true>(
375           dex_cache.Get(), type, [klass]() { return klass; })) {
376     DCHECK(Thread::Current()->IsExceptionPending());
377     return nullptr;
378   }
379 
380   if (!valid_dex_cache_method) {
381     resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
382   }
383 
384   // Note: We can check for IllegalAccessError only if we have a referrer.
385   if (kResolveMode == ResolveMode::kCheckICCEAndIAE && resolved != nullptr && referrer != nullptr) {
386     ObjPtr<mirror::Class> methods_class = resolved->GetDeclaringClass();
387     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
388     if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
389       // The referrer class can't access the method's declaring class but may still be able
390       // to access the method if the MethodId specifies an accessible subclass of the declaring
391       // class rather than the declaring class itself.
392       if (UNLIKELY(!referring_class->CanAccess(klass))) {
393         ThrowIllegalAccessErrorClassForMethodDispatch(referring_class,
394                                                       klass,
395                                                       resolved,
396                                                       type);
397         return nullptr;
398       }
399     }
400     if (UNLIKELY(!referring_class->CanAccessMember(methods_class, resolved->GetAccessFlags()))) {
401       ThrowIllegalAccessErrorMethod(referring_class, resolved);
402       return nullptr;
403     }
404   }
405 
406   // If we found a method, check for incompatible class changes.
407   if (LIKELY(resolved != nullptr) &&
408       LIKELY(kResolveMode == ResolveMode::kNoChecks ||
409              !resolved->CheckIncompatibleClassChange(type))) {
410     return resolved;
411   }
412 
413   // If we had a method, or if we can find one with another lookup type,
414   // it's an incompatible-class-change error.
415   if (resolved == nullptr) {
416     resolved = FindIncompatibleMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
417   }
418   if (resolved != nullptr) {
419     ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
420   } else {
421     // We failed to find the method (using all lookup types), so throw a NoSuchMethodError.
422     const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
423     const Signature signature = dex_file.GetMethodSignature(method_id);
424     ThrowNoSuchMethodError(type, klass, name, signature);
425   }
426   Thread::Current()->AssertPendingException();
427   return nullptr;
428 }
429 
LookupResolvedField(uint32_t field_idx,ArtMethod * referrer,bool is_static)430 inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
431                                                   ArtMethod* referrer,
432                                                   bool is_static) {
433   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
434   ArtField* field = dex_cache->GetResolvedField(field_idx);
435   if (field == nullptr) {
436     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
437     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader();
438     field = LookupResolvedField(field_idx, dex_cache, class_loader, is_static);
439   }
440   return field;
441 }
442 
ResolveField(uint32_t field_idx,ArtMethod * referrer,bool is_static)443 inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
444                                            ArtMethod* referrer,
445                                            bool is_static) {
446   Thread::PoisonObjectPointersIfDebug();
447   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
448   ArtField* resolved_field = dex_cache->GetResolvedField(field_idx);
449   if (UNLIKELY(resolved_field == nullptr)) {
450     StackHandleScope<2> hs(Thread::Current());
451     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
452     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
453     Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache));
454     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
455     resolved_field = ResolveField(field_idx, h_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 
ResolveField(uint32_t field_idx,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader,bool is_static)462 inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
463                                            Handle<mirror::DexCache> dex_cache,
464                                            Handle<mirror::ClassLoader> class_loader,
465                                            bool is_static) {
466   DCHECK(dex_cache != nullptr);
467   DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get());
468   DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
469   ArtField* resolved = dex_cache->GetResolvedField(field_idx);
470   Thread::PoisonObjectPointersIfDebug();
471   if (resolved != nullptr) {
472     return resolved;
473   }
474   const DexFile& dex_file = *dex_cache->GetDexFile();
475   const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
476   ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
477   if (klass == nullptr) {
478     DCHECK(Thread::Current()->IsExceptionPending());
479     return nullptr;
480   }
481 
482   // Look for the field again in case the type resolution updated the cache.
483   resolved = dex_cache->GetResolvedField(field_idx);
484   if (resolved != nullptr) {
485     return resolved;
486   }
487 
488   resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static);
489   if (resolved == nullptr) {
490     const char* name = dex_file.GetFieldName(field_id);
491     const char* type = dex_file.GetFieldTypeDescriptor(field_id);
492     ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
493   }
494   return resolved;
495 }
496 
497 template <typename Visitor>
VisitBootClasses(Visitor * visitor)498 inline void ClassLinker::VisitBootClasses(Visitor* visitor) {
499   boot_class_table_->Visit(*visitor);
500 }
501 
502 template <class Visitor>
VisitClassTables(const Visitor & visitor)503 inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
504   Thread* const self = Thread::Current();
505   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
506   for (const ClassLoaderData& data : class_loaders_) {
507     if (data.class_table != nullptr) {
508       visitor(data.class_table);
509     }
510   }
511 }
512 
513 template <ReadBarrierOption kReadBarrierOption>
GetClassRoots()514 inline ObjPtr<mirror::ObjectArray<mirror::Class>> ClassLinker::GetClassRoots() {
515   ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
516       class_roots_.Read<kReadBarrierOption>();
517   DCHECK(class_roots != nullptr);
518   return class_roots;
519 }
520 
521 template <typename Visitor>
VisitKnownDexFiles(Thread * self,Visitor visitor)522 void ClassLinker::VisitKnownDexFiles(Thread* self, Visitor visitor) {
523   ReaderMutexLock rmu(self, *Locks::dex_lock_);
524   std::for_each(dex_caches_.begin(),
525                 dex_caches_.end(),
526                 [&](const auto& entry) REQUIRES(Locks::mutator_lock_) {
527                   visitor(/*dex_file=*/entry.first);
528                 });
529 }
530 
531 }  // namespace art
532 
533 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
534