• 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 "art_field-inl.h"
23 #include "art_method-inl.h"
24 #include "base/mutex.h"
25 #include "class_linker.h"
26 #include "dex/dex_file.h"
27 #include "dex/dex_file_structs.h"
28 #include "gc_root-inl.h"
29 #include "handle_scope-inl.h"
30 #include "mirror/class_loader.h"
31 #include "mirror/dex_cache-inl.h"
32 #include "mirror/iftable.h"
33 #include "mirror/object_array-inl.h"
34 #include "obj_ptr-inl.h"
35 #include "scoped_thread_state_change-inl.h"
36 
37 namespace art {
38 
FindArrayClass(Thread * self,ObjPtr<mirror::Class> element_class)39 inline ObjPtr<mirror::Class> ClassLinker::FindArrayClass(Thread* self,
40                                                          ObjPtr<mirror::Class> element_class) {
41   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
42     // Read the cached array class once to avoid races with other threads setting it.
43     ObjPtr<mirror::Class> array_class = find_array_class_cache_[i].Read();
44     if (array_class != nullptr && array_class->GetComponentType() == element_class) {
45       return array_class;
46     }
47   }
48   std::string descriptor = "[";
49   std::string temp;
50   descriptor += element_class->GetDescriptor(&temp);
51   StackHandleScope<1> hs(Thread::Current());
52   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(element_class->GetClassLoader()));
53   ObjPtr<mirror::Class> array_class = FindClass(self, descriptor.c_str(), class_loader);
54   if (array_class != nullptr) {
55     // Benign races in storing array class and incrementing index.
56     size_t victim_index = find_array_class_cache_next_victim_;
57     find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
58     find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
59   } else {
60     // We should have a NoClassDefFoundError.
61     self->AssertPendingException();
62   }
63   return array_class;
64 }
65 
ResolveString(dex::StringIndex string_idx,ArtField * referrer)66 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
67                                                          ArtField* referrer) {
68   Thread::PoisonObjectPointersIfDebug();
69   DCHECK(!Thread::Current()->IsExceptionPending());
70   // We do not need the read barrier for getting the DexCache for the initial resolved type
71   // lookup as both from-space and to-space copies point to the same native resolved types array.
72   ObjPtr<mirror::String> resolved =
73       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
74   if (resolved == nullptr) {
75     resolved = DoResolveString(string_idx, referrer->GetDexCache());
76   }
77   return resolved;
78 }
79 
ResolveString(dex::StringIndex string_idx,ArtMethod * referrer)80 inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
81                                                          ArtMethod* referrer) {
82   Thread::PoisonObjectPointersIfDebug();
83   DCHECK(!Thread::Current()->IsExceptionPending());
84   // We do not need the read barrier for getting the DexCache for the initial resolved type
85   // lookup as both from-space and to-space copies point to the same native resolved types array.
86   ObjPtr<mirror::String> resolved =
87       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
88   if (resolved == nullptr) {
89     resolved = DoResolveString(string_idx, referrer->GetDexCache());
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   // We do not need the read barrier for getting the DexCache for the initial resolved type
123   // lookup as both from-space and to-space copies point to the same native resolved types array.
124   ObjPtr<mirror::Class> resolved_type =
125       referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
126   if (resolved_type == nullptr) {
127     resolved_type = DoResolveType(type_idx, referrer);
128   }
129   return resolved_type;
130 }
131 
ResolveType(dex::TypeIndex type_idx,ArtField * referrer)132 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
133                                                       ArtField* referrer) {
134   Thread::PoisonObjectPointersIfDebug();
135   DCHECK(!Thread::Current()->IsExceptionPending());
136   // We do not need the read barrier for getting the DexCache for the initial resolved type
137   // lookup as both from-space and to-space copies point to the same native resolved types array.
138   ObjPtr<mirror::Class> resolved_type =
139       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
140   if (UNLIKELY(resolved_type == nullptr)) {
141     resolved_type = DoResolveType(type_idx, referrer);
142   }
143   return resolved_type;
144 }
145 
ResolveType(dex::TypeIndex type_idx,ArtMethod * referrer)146 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
147                                                       ArtMethod* referrer) {
148   Thread::PoisonObjectPointersIfDebug();
149   DCHECK(!Thread::Current()->IsExceptionPending());
150   // We do not need the read barrier for getting the DexCache for the initial resolved type
151   // lookup as both from-space and to-space copies point to the same native resolved types array.
152   ObjPtr<mirror::Class> resolved_type =
153       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
154   if (UNLIKELY(resolved_type == nullptr)) {
155     resolved_type = DoResolveType(type_idx, referrer);
156   }
157   return resolved_type;
158 }
159 
ResolveType(dex::TypeIndex type_idx,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader)160 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
161                                                       Handle<mirror::DexCache> dex_cache,
162                                                       Handle<mirror::ClassLoader> class_loader) {
163   DCHECK(dex_cache != nullptr);
164   Thread::PoisonObjectPointersIfDebug();
165   ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
166   if (resolved == nullptr) {
167     resolved = DoResolveType(type_idx, dex_cache, class_loader);
168   }
169   return resolved;
170 }
171 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::Class> referrer)172 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
173                                                              ObjPtr<mirror::Class> 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 =
177       referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
178   if (type == nullptr) {
179     type = DoLookupResolvedType(type_idx, referrer);
180   }
181   return type;
182 }
183 
LookupResolvedType(dex::TypeIndex type_idx,ArtField * referrer)184 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
185                                                              ArtField* 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 =
189       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
190   if (type == nullptr) {
191     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
192   }
193   return type;
194 }
195 
LookupResolvedType(dex::TypeIndex type_idx,ArtMethod * referrer)196 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
197                                                              ArtMethod* referrer) {
198   // We do not need the read barrier for getting the DexCache for the initial resolved type
199   // lookup as both from-space and to-space copies point to the same native resolved types array.
200   ObjPtr<mirror::Class> type =
201       referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
202   if (type == nullptr) {
203     type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
204   }
205   return type;
206 }
207 
LookupResolvedType(dex::TypeIndex type_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)208 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
209     dex::TypeIndex type_idx,
210     ObjPtr<mirror::DexCache> dex_cache,
211     ObjPtr<mirror::ClassLoader> class_loader) {
212   ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
213   if (type == nullptr) {
214     type = DoLookupResolvedType(type_idx, dex_cache, class_loader);
215   }
216   return type;
217 }
218 
219 template <bool kThrowOnError, typename ClassGetter>
CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,InvokeType type,ClassGetter class_getter)220 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
221                                                   InvokeType type,
222                                                   ClassGetter class_getter) {
223   switch (type) {
224     case kStatic:
225     case kSuper:
226       break;
227     case kInterface: {
228       // We have to check whether the method id really belongs to an interface (dex static bytecode
229       // constraints A15, A16). Otherwise you must not invoke-interface on it.
230       ObjPtr<mirror::Class> klass = class_getter();
231       if (UNLIKELY(!klass->IsInterface())) {
232         if (kThrowOnError) {
233           ThrowIncompatibleClassChangeError(klass,
234                                             "Found class %s, but interface was expected",
235                                             klass->PrettyDescriptor().c_str());
236         }
237         return true;
238       }
239       break;
240     }
241     case kDirect:
242       if (dex_cache->GetDexFile()->SupportsDefaultMethods()) {
243         break;
244       }
245       FALLTHROUGH_INTENDED;
246     case kVirtual: {
247       // Similarly, invoke-virtual (and invoke-direct without default methods) must reference
248       // a non-interface class (dex static bytecode constraint A24, A25).
249       ObjPtr<mirror::Class> klass = class_getter();
250       if (UNLIKELY(klass->IsInterface())) {
251         if (kThrowOnError) {
252           ThrowIncompatibleClassChangeError(klass,
253                                             "Found interface %s, but class was expected",
254                                             klass->PrettyDescriptor().c_str());
255         }
256         return true;
257       }
258       break;
259     }
260     default:
261       LOG(FATAL) << "Unreachable - invocation type: " << type;
262       UNREACHABLE();
263   }
264   return false;
265 }
266 
267 template <bool kThrow>
CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,InvokeType type,uint32_t method_idx,ObjPtr<mirror::ClassLoader> class_loader)268 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
269                                                   InvokeType type,
270                                                   uint32_t method_idx,
271                                                   ObjPtr<mirror::ClassLoader> class_loader) {
272   return CheckInvokeClassMismatch<kThrow>(
273       dex_cache,
274       type,
275       [this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
276         const dex::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
277         ObjPtr<mirror::Class> klass =
278             LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
279         DCHECK(klass != nullptr);
280         return klass;
281       });
282 }
283 
LookupResolvedMethod(uint32_t method_idx,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::ClassLoader> class_loader)284 inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
285                                                     ObjPtr<mirror::DexCache> dex_cache,
286                                                     ObjPtr<mirror::ClassLoader> class_loader) {
287   PointerSize pointer_size = image_pointer_size_;
288   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, pointer_size);
289   if (resolved == nullptr) {
290     const DexFile& dex_file = *dex_cache->GetDexFile();
291     const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
292     ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
293     if (klass != nullptr) {
294       resolved = FindResolvedMethod(klass, dex_cache, class_loader, method_idx);
295     }
296   }
297   return resolved;
298 }
299 
300 template <InvokeType type, ClassLinker::ResolveMode kResolveMode>
GetResolvedMethod(uint32_t method_idx,ArtMethod * referrer)301 inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) {
302   DCHECK(referrer != nullptr);
303   // Note: The referrer can be a Proxy constructor. In that case, we need to do the
304   // lookup in the context of the original method from where it steals the code.
305   // However, we delay the GetInterfaceMethodIfProxy() until needed.
306   DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
307   // We do not need the read barrier for getting the DexCache for the initial resolved method
308   // lookup as both from-space and to-space copies point to the same native resolved methods array.
309   ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
310       method_idx, image_pointer_size_);
311   if (resolved_method == nullptr) {
312     return nullptr;
313   }
314   DCHECK(!resolved_method->IsRuntimeMethod());
315   if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
316     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
317     // Check if the invoke type matches the class type.
318     ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
319     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetClassLoader();
320     if (CheckInvokeClassMismatch</* kThrow= */ false>(dex_cache, type, method_idx, class_loader)) {
321       return nullptr;
322     }
323     // Check access.
324     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
325     if (!referring_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
326                                                   resolved_method,
327                                                   dex_cache,
328                                                   method_idx)) {
329       return nullptr;
330     }
331     // Check if the invoke type matches the method type.
332     if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
333       return nullptr;
334     }
335   }
336   return resolved_method;
337 }
338 
339 template <ClassLinker::ResolveMode kResolveMode>
ResolveMethod(Thread * self,uint32_t method_idx,ArtMethod * referrer,InvokeType type)340 inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
341                                              uint32_t method_idx,
342                                              ArtMethod* referrer,
343                                              InvokeType type) {
344   DCHECK(referrer != nullptr);
345   // Note: The referrer can be a Proxy constructor. In that case, we need to do the
346   // lookup in the context of the original method from where it steals the code.
347   // However, we delay the GetInterfaceMethodIfProxy() until needed.
348   DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
349   Thread::PoisonObjectPointersIfDebug();
350   // We do not need the read barrier for getting the DexCache for the initial resolved method
351   // lookup as both from-space and to-space copies point to the same native resolved methods array.
352   ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
353       method_idx, image_pointer_size_);
354   DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod());
355   if (UNLIKELY(resolved_method == nullptr)) {
356     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
357     ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
358     StackHandleScope<2> hs(self);
359     Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
360     Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
361     resolved_method = ResolveMethod<kResolveMode>(method_idx,
362                                                   h_dex_cache,
363                                                   h_class_loader,
364                                                   referrer,
365                                                   type);
366   } else if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
367     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
368     // Check if the invoke type matches the class type.
369     ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
370     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetClassLoader();
371     if (CheckInvokeClassMismatch</* kThrow= */ true>(dex_cache, type, method_idx, class_loader)) {
372       DCHECK(Thread::Current()->IsExceptionPending());
373       return nullptr;
374     }
375     // Check access.
376     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
377     if (!referring_class->CheckResolvedMethodAccess(resolved_method->GetDeclaringClass(),
378                                                     resolved_method,
379                                                     dex_cache,
380                                                     method_idx,
381                                                     type)) {
382       DCHECK(Thread::Current()->IsExceptionPending());
383       return nullptr;
384     }
385     // Check if the invoke type matches the method type.
386     if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
387       ThrowIncompatibleClassChangeError(type,
388                                         resolved_method->GetInvokeType(),
389                                         resolved_method,
390                                         referrer);
391       return nullptr;
392     }
393   }
394   // Note: We cannot check here to see whether we added the method to the cache. It
395   //       might be an erroneous class, which results in it being hidden from us.
396   return resolved_method;
397 }
398 
LookupResolvedField(uint32_t field_idx,ArtMethod * referrer,bool is_static)399 inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
400                                                   ArtMethod* referrer,
401                                                   bool is_static) {
402   // We do not need the read barrier for getting the DexCache for the initial resolved field
403   // lookup as both from-space and to-space copies point to the same native resolved fields array.
404   ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
405       field_idx, image_pointer_size_);
406   if (field == nullptr) {
407     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader();
408     field = LookupResolvedField(field_idx, referrer->GetDexCache(), class_loader, is_static);
409   }
410   return field;
411 }
412 
ResolveField(uint32_t field_idx,ArtMethod * referrer,bool is_static)413 inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
414                                            ArtMethod* referrer,
415                                            bool is_static) {
416   Thread::PoisonObjectPointersIfDebug();
417   // We do not need the read barrier for getting the DexCache for the initial resolved field
418   // lookup as both from-space and to-space copies point to the same native resolved fields array.
419   ArtField* resolved_field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
420       field_idx, image_pointer_size_);
421   if (UNLIKELY(resolved_field == nullptr)) {
422     StackHandleScope<2> hs(Thread::Current());
423     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
424     Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
425     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
426     resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static);
427     // Note: We cannot check here to see whether we added the field to the cache. The type
428     //       might be an erroneous class, which results in it being hidden from us.
429   }
430   return resolved_field;
431 }
432 
433 template <class Visitor>
VisitClassTables(const Visitor & visitor)434 inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
435   Thread* const self = Thread::Current();
436   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
437   for (const ClassLoaderData& data : class_loaders_) {
438     if (data.class_table != nullptr) {
439       visitor(data.class_table);
440     }
441   }
442 }
443 
444 template <ReadBarrierOption kReadBarrierOption>
GetClassRoots()445 inline ObjPtr<mirror::ObjectArray<mirror::Class>> ClassLinker::GetClassRoots() {
446   ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
447       class_roots_.Read<kReadBarrierOption>();
448   DCHECK(class_roots != nullptr);
449   return class_roots;
450 }
451 
452 }  // namespace art
453 
454 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
455