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