xref: /aosp_15_r20/art/runtime/class_linker-inl.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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-inl.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 =
47         find_array_class_cache_[i].load(std::memory_order_acquire).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 =
58       FindClass(self, descriptor.c_str(), descriptor.length(), class_loader);
59   if (array_class != nullptr) {
60     // Benign races in storing array class and incrementing index.
61     size_t victim_index = find_array_class_cache_next_victim_;
62     find_array_class_cache_[victim_index].store(GcRoot<mirror::Class>(array_class),
63                                                 std::memory_order_release);
64     find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
65   } else {
66     // We should have a NoClassDefFoundError.
67     self->AssertPendingException();
68   }
69   return array_class;
70 }
71 
ResolveString(dex::StringIndex string_idx,ArtField * referrer)72 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
73                                                          ArtField* referrer) {
74   Thread::PoisonObjectPointersIfDebug();
75   DCHECK(!Thread::Current()->IsExceptionPending());
76   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
77   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
78   if (resolved == nullptr) {
79     resolved = DoResolveString(string_idx, dex_cache);
80   }
81   return resolved;
82 }
83 
ResolveString(dex::StringIndex string_idx,ArtMethod * referrer)84 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
85                                                          ArtMethod* referrer) {
86   Thread::PoisonObjectPointersIfDebug();
87   DCHECK(!Thread::Current()->IsExceptionPending());
88   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
89   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
90   if (resolved == nullptr) {
91     resolved = DoResolveString(string_idx, dex_cache);
92   }
93   return resolved;
94 }
95 
ResolveString(dex::StringIndex string_idx,Handle<mirror::DexCache> dex_cache)96 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
97                                                          Handle<mirror::DexCache> dex_cache) {
98   Thread::PoisonObjectPointersIfDebug();
99   DCHECK(!Thread::Current()->IsExceptionPending());
100   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
101   if (resolved == nullptr) {
102     resolved = DoResolveString(string_idx, dex_cache);
103   }
104   return resolved;
105 }
106 
LookupString(dex::StringIndex string_idx,ObjPtr<mirror::DexCache> dex_cache)107 inline ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
108                                                         ObjPtr<mirror::DexCache> dex_cache) {
109   ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
110   if (resolved == nullptr) {
111     resolved = DoLookupString(string_idx, dex_cache);
112   }
113   return resolved;
114 }
115 
ResolveType(dex::TypeIndex type_idx,ObjPtr<mirror::Class> referrer)116 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
117                                                       ObjPtr<mirror::Class> referrer) {
118   if (kObjPtrPoisoning) {
119     StackHandleScope<1> hs(Thread::Current());
120     HandleWrapperObjPtr<mirror::Class> referrer_wrapper = hs.NewHandleWrapper(&referrer);
121     Thread::Current()->PoisonObjectPointers();
122   }
123   DCHECK(!Thread::Current()->IsExceptionPending());
124   ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
125   if (resolved_type == nullptr) {
126     resolved_type = DoResolveType(type_idx, referrer);
127   }
128   return resolved_type;
129 }
130 
ResolveType(dex::TypeIndex type_idx,ArtField * referrer)131 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
132                                                       ArtField* referrer) {
133   Thread::PoisonObjectPointersIfDebug();
134   DCHECK(!Thread::Current()->IsExceptionPending());
135   ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
136   if (UNLIKELY(resolved_type == nullptr)) {
137     resolved_type = DoResolveType(type_idx, referrer);
138   }
139   return resolved_type;
140 }
141 
ResolveType(dex::TypeIndex type_idx,ArtMethod * referrer)142 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
143                                                       ArtMethod* referrer) {
144   Thread::PoisonObjectPointersIfDebug();
145   DCHECK(!Thread::Current()->IsExceptionPending());
146   ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
147   if (UNLIKELY(resolved_type == nullptr)) {
148     resolved_type = DoResolveType(type_idx, referrer);
149   }
150   return resolved_type;
151 }
152 
ResolveType(dex::TypeIndex type_idx,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader)153 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
154                                                       Handle<mirror::DexCache> dex_cache,
155                                                       Handle<mirror::ClassLoader> class_loader) {
156   DCHECK(dex_cache != nullptr);
157   DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
158   Thread::PoisonObjectPointersIfDebug();
159   ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
160   if (resolved == nullptr) {
161     resolved = DoResolveType(type_idx, dex_cache, class_loader);
162   }
163   return resolved;
164 }
165 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::Class> referrer)166 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
167                                                              ObjPtr<mirror::Class> referrer) {
168   ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx);
169   if (type == nullptr) {
170     type = DoLookupResolvedType(type_idx, referrer);
171   }
172   return type;
173 }
174 
LookupResolvedType(dex::TypeIndex type_idx,ArtField * referrer)175 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
176                                                              ArtField* 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 = referrer->GetDexCache()->GetResolvedType(type_idx);
180   if (type == nullptr) {
181     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
182   }
183   return type;
184 }
185 
LookupResolvedType(dex::TypeIndex type_idx,ArtMethod * referrer)186 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
187                                                              ArtMethod* referrer) {
188   // We do not need the read barrier for getting the DexCache for the initial resolved type
189   // lookup as both from-space and to-space copies point to the same native resolved types array.
190   ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx);
191   if (type == nullptr) {
192     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
193   }
194   return type;
195 }
196 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)197 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
198     dex::TypeIndex type_idx,
199     ObjPtr<mirror::DexCache> dex_cache,
200     ObjPtr<mirror::ClassLoader> class_loader) {
201   DCHECK(dex_cache->GetClassLoader() == class_loader);
202   ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
203   if (type == nullptr) {
204     type = DoLookupResolvedType(type_idx, dex_cache, class_loader);
205   }
206   return type;
207 }
208 
LookupResolvedMethod(uint32_t method_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)209 inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
210                                                     ObjPtr<mirror::DexCache> dex_cache,
211                                                     ObjPtr<mirror::ClassLoader> class_loader) {
212   DCHECK(dex_cache->GetClassLoader() == class_loader);
213   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
214   if (resolved == nullptr) {
215     const DexFile& dex_file = *dex_cache->GetDexFile();
216     const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
217     ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
218     if (klass != nullptr) {
219       resolved = FindResolvedMethod(klass, dex_cache, class_loader, method_idx);
220     }
221   }
222   return resolved;
223 }
224 
ResolveMethodId(uint32_t method_idx,ArtMethod * referrer)225 inline ArtMethod* ClassLinker::ResolveMethodId(uint32_t method_idx, ArtMethod* referrer) {
226   ArtMethod* resolved = referrer->GetDexCache()->GetResolvedMethod(method_idx);
227   if (resolved != nullptr) {
228     DCHECK(!resolved->IsRuntimeMethod());
229     DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
230     return resolved;
231   }
232   // Fail, get the declaring class.
233   referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
234   const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
235   ObjPtr<mirror::Class> klass = ResolveType(method_id.class_idx_, referrer);
236   if (klass == nullptr) {
237     Thread::Current()->AssertPendingException();
238     return nullptr;
239   }
240 
241   resolved =
242       FindResolvedMethod(klass, referrer->GetDexCache(), referrer->GetClassLoader(), method_idx);
243   if (resolved != nullptr) {
244     return resolved;
245   }
246 
247   const char* name = referrer->GetDexFile()->GetStringData(method_id.name_idx_);
248   const Signature signature = referrer->GetDexFile()->GetMethodSignature(method_id);
249   ThrowNoSuchMethodError(klass, name, signature);
250   return nullptr;
251 }
252 
ThrowIfInvokeClassMismatch(ObjPtr<mirror::Class> klass,const DexFile & dex_file,InvokeType type)253 inline bool ClassLinker::ThrowIfInvokeClassMismatch(ObjPtr<mirror::Class> klass,
254                                                     const DexFile& dex_file,
255                                                     InvokeType type) {
256   if (type == kInterface) {
257     if (UNLIKELY(!klass->IsInterface())) {
258       ThrowIncompatibleClassChangeError(klass,
259                                         "Found class %s, but interface was expected",
260                                         klass->PrettyDescriptor().c_str());
261       return true;
262     }
263   } else if (type == kVirtual) {
264     if (UNLIKELY(klass->IsInterface())) {
265       ThrowIncompatibleClassChangeError(klass,
266                                         "Found interface %s, but class was expected",
267                                         klass->PrettyDescriptor().c_str());
268       return true;
269     }
270   } else if (type == kDirect) {
271     if (UNLIKELY(klass->IsInterface()) && !dex_file.SupportsDefaultMethods()) {
272       ThrowIncompatibleClassChangeError(klass,
273                                         "Found interface %s, but class was expected",
274                                         klass->PrettyDescriptor().c_str());
275       return true;
276     }
277   }
278   return false;
279 }
280 
ResolveMethodWithChecks(uint32_t method_idx,ArtMethod * referrer,InvokeType type)281 inline ArtMethod* ClassLinker::ResolveMethodWithChecks(uint32_t method_idx,
282                                                        ArtMethod* referrer,
283                                                        InvokeType type) {
284   DCHECK(referrer != nullptr);
285   DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor());
286 
287   // For a Proxy constructor, we need to do the lookup in the context of the original method
288   // from where it steals the code.
289   referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
290 
291   const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
292   ObjPtr<mirror::Class> klass = ResolveType(method_id.class_idx_, referrer);
293   if (klass == nullptr || ThrowIfInvokeClassMismatch(klass, *referrer->GetDexFile(), type)) {
294     DCHECK(Thread::Current()->IsExceptionPending());
295     return nullptr;
296   }
297 
298   ArtMethod* resolved = referrer->GetDexCache()->GetResolvedMethod(method_idx);
299   if (resolved == nullptr) {
300     resolved = FindResolvedMethod(klass,
301                                   referrer->GetDexCache(),
302                                   referrer->GetDexCache()->GetClassLoader(),
303                                   method_idx);
304   }
305 
306   if (resolved != nullptr) {
307     ObjPtr<mirror::Class> methods_class = resolved->GetDeclaringClass();
308     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
309     if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
310       // The referrer class can't access the method's declaring class but may still be able
311       // to access the method if the MethodId specifies an accessible subclass of the declaring
312       // class rather than the declaring class itself.
313       if (UNLIKELY(!referring_class->CanAccess(klass))) {
314         ThrowIllegalAccessErrorClassForMethodDispatch(referring_class,
315                                                       klass,
316                                                       resolved,
317                                                       type);
318         return nullptr;
319       }
320     }
321     if (UNLIKELY(!referring_class->CanAccessMember(methods_class, resolved->GetAccessFlags()))) {
322       ThrowIllegalAccessErrorMethod(referring_class, resolved);
323       return nullptr;
324     }
325 
326     if (LIKELY(!resolved->CheckIncompatibleClassChange(type))) {
327       return resolved;
328     }
329   } else {
330     resolved = FindIncompatibleMethod(klass,
331                                       referrer->GetDexCache(),
332                                       referrer->GetDexCache()->GetClassLoader(),
333                                       method_idx);
334   }
335   if (resolved != nullptr) {
336     ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
337     return nullptr;
338   }
339 
340   // We failed to find the method (using all lookup types), so throw a NoSuchMethodError.
341   const char* name = referrer->GetDexFile()->GetStringData(method_id.name_idx_);
342   const Signature signature = referrer->GetDexFile()->GetMethodSignature(method_id);
343   ThrowNoSuchMethodError(type, klass, name, signature);
344   return nullptr;
345 }
346 
LookupResolvedField(uint32_t field_idx,ArtMethod * referrer,bool is_static)347 inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
348                                                   ArtMethod* referrer,
349                                                   bool is_static) {
350   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
351   ArtField* field = dex_cache->GetResolvedField(field_idx);
352   if (field == nullptr) {
353     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
354     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader();
355     field = LookupResolvedField(field_idx, dex_cache, class_loader, is_static);
356   }
357   return field;
358 }
359 
ResolveField(uint32_t field_idx,ArtMethod * referrer,bool is_static)360 inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
361                                            ArtMethod* referrer,
362                                            bool is_static) {
363   Thread::PoisonObjectPointersIfDebug();
364   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
365   ArtField* resolved_field = dex_cache->GetResolvedField(field_idx);
366   if (UNLIKELY(resolved_field == nullptr)) {
367     StackHandleScope<2> hs(Thread::Current());
368     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
369     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
370     Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache));
371     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
372     resolved_field = ResolveField(field_idx, h_dex_cache, class_loader, is_static);
373     // Note: We cannot check here to see whether we added the field to the cache. The type
374     //       might be an erroneous class, which results in it being hidden from us.
375   }
376   return resolved_field;
377 }
378 
ResolveField(uint32_t field_idx,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader,bool is_static)379 inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
380                                            Handle<mirror::DexCache> dex_cache,
381                                            Handle<mirror::ClassLoader> class_loader,
382                                            bool is_static) {
383   DCHECK(dex_cache != nullptr);
384   DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get());
385   DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
386   ArtField* resolved = dex_cache->GetResolvedField(field_idx);
387   Thread::PoisonObjectPointersIfDebug();
388   if (resolved != nullptr) {
389     return resolved;
390   }
391   const DexFile& dex_file = *dex_cache->GetDexFile();
392   const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
393   ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
394   if (klass == nullptr) {
395     DCHECK(Thread::Current()->IsExceptionPending());
396     return nullptr;
397   }
398 
399   // Look for the field again in case the type resolution updated the cache.
400   resolved = dex_cache->GetResolvedField(field_idx);
401   if (resolved != nullptr) {
402     return resolved;
403   }
404 
405   resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static);
406   if (resolved == nullptr) {
407     const char* name = dex_file.GetFieldName(field_id);
408     const char* type = dex_file.GetFieldTypeDescriptor(field_id);
409     ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
410   }
411   return resolved;
412 }
413 
414 template <typename Visitor>
VisitBootClasses(Visitor * visitor)415 inline void ClassLinker::VisitBootClasses(Visitor* visitor) {
416   boot_class_table_->Visit(*visitor);
417 }
418 
419 template <class Visitor>
VisitClassTables(const Visitor & visitor)420 inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
421   Thread* const self = Thread::Current();
422   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
423   for (const ClassLoaderData& data : class_loaders_) {
424     if (data.class_table != nullptr) {
425       visitor(data.class_table);
426     }
427   }
428 }
429 
430 template <ReadBarrierOption kReadBarrierOption>
GetClassRoots()431 inline ObjPtr<mirror::ObjectArray<mirror::Class>> ClassLinker::GetClassRoots() {
432   ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
433       class_roots_.Read<kReadBarrierOption>();
434   DCHECK(class_roots != nullptr);
435   return class_roots;
436 }
437 
438 template <typename Visitor>
VisitKnownDexFiles(Thread * self,Visitor visitor)439 void ClassLinker::VisitKnownDexFiles(Thread* self, Visitor visitor) {
440   ReaderMutexLock rmu(self, *Locks::dex_lock_);
441   std::for_each(dex_caches_.begin(),
442                 dex_caches_.end(),
443                 [&](const auto& entry) REQUIRES(Locks::mutator_lock_) {
444                   visitor(/*dex_file=*/entry.first);
445                 });
446 }
447 
448 }  // namespace art
449 
450 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
451