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