Home | History | Annotate | Download | only in runtime
      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 "art_field.h"
     21 #include "class_linker.h"
     22 #include "gc_root-inl.h"
     23 #include "gc/heap-inl.h"
     24 #include "obj_ptr-inl.h"
     25 #include "mirror/class_loader.h"
     26 #include "mirror/dex_cache-inl.h"
     27 #include "mirror/iftable.h"
     28 #include "mirror/object_array-inl.h"
     29 #include "handle_scope-inl.h"
     30 #include "scoped_thread_state_change-inl.h"
     31 
     32 #include <atomic>
     33 
     34 namespace art {
     35 
     36 inline mirror::Class* ClassLinker::FindArrayClass(Thread* self,
     37                                                   ObjPtr<mirror::Class>* element_class) {
     38   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
     39     // Read the cached array class once to avoid races with other threads setting it.
     40     ObjPtr<mirror::Class> array_class = find_array_class_cache_[i].Read();
     41     if (array_class != nullptr && array_class->GetComponentType() == *element_class) {
     42       return array_class.Ptr();
     43     }
     44   }
     45   std::string descriptor = "[";
     46   std::string temp;
     47   descriptor += (*element_class)->GetDescriptor(&temp);
     48   StackHandleScope<2> hs(Thread::Current());
     49   Handle<mirror::ClassLoader> class_loader(hs.NewHandle((*element_class)->GetClassLoader()));
     50   HandleWrapperObjPtr<mirror::Class> h_element_class(hs.NewHandleWrapper(element_class));
     51   ObjPtr<mirror::Class> array_class = FindClass(self, descriptor.c_str(), class_loader);
     52   if (array_class != nullptr) {
     53     // Benign races in storing array class and incrementing index.
     54     size_t victim_index = find_array_class_cache_next_victim_;
     55     find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
     56     find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
     57   } else {
     58     // We should have a NoClassDefFoundError.
     59     self->AssertPendingException();
     60   }
     61   return array_class.Ptr();
     62 }
     63 
     64 inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
     65     dex::TypeIndex type_idx,
     66     ObjPtr<mirror::DexCache> dex_cache,
     67     ObjPtr<mirror::ClassLoader> class_loader) {
     68   ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
     69   if (type == nullptr) {
     70     type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
     71         *dex_cache->GetDexFile(), type_idx, dex_cache, class_loader);
     72   }
     73   return type;
     74 }
     75 
     76 inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) {
     77   Thread::PoisonObjectPointersIfDebug();
     78   if (kIsDebugBuild) {
     79     Thread::Current()->AssertNoPendingException();
     80   }
     81   ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
     82   if (UNLIKELY(resolved_type == nullptr)) {
     83     StackHandleScope<2> hs(Thread::Current());
     84     ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
     85     Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
     86     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
     87     const DexFile& dex_file = *dex_cache->GetDexFile();
     88     resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
     89   }
     90   return resolved_type.Ptr();
     91 }
     92 
     93 template <bool kThrowOnError, typename ClassGetter>
     94 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
     95                                                   InvokeType type,
     96                                                   ClassGetter class_getter) {
     97   switch (type) {
     98     case kStatic:
     99     case kSuper:
    100       break;
    101     case kInterface: {
    102       // We have to check whether the method id really belongs to an interface (dex static bytecode
    103       // constraints A15, A16). Otherwise you must not invoke-interface on it.
    104       ObjPtr<mirror::Class> klass = class_getter();
    105       if (UNLIKELY(!klass->IsInterface())) {
    106         if (kThrowOnError) {
    107           ThrowIncompatibleClassChangeError(klass,
    108                                             "Found class %s, but interface was expected",
    109                                             klass->PrettyDescriptor().c_str());
    110         }
    111         return true;
    112       }
    113       break;
    114     }
    115     case kDirect:
    116       if (dex_cache->GetDexFile()->GetVersion() >= DexFile::kDefaultMethodsVersion) {
    117         break;
    118       }
    119       FALLTHROUGH_INTENDED;
    120     case kVirtual: {
    121       // Similarly, invoke-virtual (and invoke-direct without default methods) must reference
    122       // a non-interface class (dex static bytecode constraint A24, A25).
    123       ObjPtr<mirror::Class> klass = class_getter();
    124       if (UNLIKELY(klass->IsInterface())) {
    125         if (kThrowOnError) {
    126           ThrowIncompatibleClassChangeError(klass,
    127                                             "Found interface %s, but class was expected",
    128                                             klass->PrettyDescriptor().c_str());
    129         }
    130         return true;
    131       }
    132       break;
    133     }
    134     default:
    135       LOG(FATAL) << "Unreachable - invocation type: " << type;
    136       UNREACHABLE();
    137   }
    138   return false;
    139 }
    140 
    141 template <bool kThrow>
    142 inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
    143                                                   InvokeType type,
    144                                                   uint32_t method_idx,
    145                                                   ObjPtr<mirror::ClassLoader> class_loader) {
    146   return CheckInvokeClassMismatch<kThrow>(
    147       dex_cache,
    148       type,
    149       [this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
    150         const DexFile& dex_file = *dex_cache->GetDexFile();
    151         const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
    152         ObjPtr<mirror::Class> klass =
    153             LookupResolvedType(dex_file, method_id.class_idx_, dex_cache, class_loader);
    154         DCHECK(klass != nullptr);
    155         return klass;
    156       });
    157 }
    158 
    159 inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
    160                                                     ObjPtr<mirror::DexCache> dex_cache,
    161                                                     ObjPtr<mirror::ClassLoader> class_loader) {
    162   PointerSize pointer_size = image_pointer_size_;
    163   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, pointer_size);
    164   if (resolved == nullptr) {
    165     const DexFile& dex_file = *dex_cache->GetDexFile();
    166     const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
    167     ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
    168     if (klass != nullptr) {
    169       if (klass->IsInterface()) {
    170         resolved = klass->FindInterfaceMethod(dex_cache, method_idx, pointer_size);
    171       } else {
    172         resolved = klass->FindClassMethod(dex_cache, method_idx, pointer_size);
    173       }
    174       if (resolved != nullptr) {
    175         dex_cache->SetResolvedMethod(method_idx, resolved, pointer_size);
    176       }
    177     }
    178   }
    179   return resolved;
    180 }
    181 
    182 template <InvokeType type, ClassLinker::ResolveMode kResolveMode>
    183 inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) {
    184   DCHECK(referrer != nullptr);
    185   // Note: The referrer can be a Proxy constructor. In that case, we need to do the
    186   // lookup in the context of the original method from where it steals the code.
    187   // However, we delay the GetInterfaceMethodIfProxy() until needed.
    188   DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
    189   ArtMethod* resolved_method = referrer->GetDexCacheResolvedMethod(method_idx, image_pointer_size_);
    190   if (resolved_method == nullptr) {
    191     return nullptr;
    192   }
    193   DCHECK(!resolved_method->IsRuntimeMethod());
    194   if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
    195     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    196     // Check if the invoke type matches the class type.
    197     ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
    198     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetClassLoader();
    199     if (CheckInvokeClassMismatch</* kThrow */ false>(dex_cache, type, method_idx, class_loader)) {
    200       return nullptr;
    201     }
    202     // Check access.
    203     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
    204     if (!referring_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
    205                                                   resolved_method,
    206                                                   dex_cache,
    207                                                   method_idx)) {
    208       return nullptr;
    209     }
    210     // Check if the invoke type matches the method type.
    211     if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
    212       return nullptr;
    213     }
    214   }
    215   return resolved_method;
    216 }
    217 
    218 template <ClassLinker::ResolveMode kResolveMode>
    219 inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
    220                                              uint32_t method_idx,
    221                                              ArtMethod* referrer,
    222                                              InvokeType type) {
    223   DCHECK(referrer != nullptr);
    224   // Note: The referrer can be a Proxy constructor. In that case, we need to do the
    225   // lookup in the context of the original method from where it steals the code.
    226   // However, we delay the GetInterfaceMethodIfProxy() until needed.
    227   DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
    228   Thread::PoisonObjectPointersIfDebug();
    229   ArtMethod* resolved_method = referrer->GetDexCacheResolvedMethod(method_idx, image_pointer_size_);
    230   DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod());
    231   if (UNLIKELY(resolved_method == nullptr)) {
    232     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    233     ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
    234     StackHandleScope<2> hs(self);
    235     Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
    236     Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
    237     const DexFile* dex_file = h_dex_cache->GetDexFile();
    238     resolved_method = ResolveMethod<kResolveMode>(*dex_file,
    239                                                   method_idx,
    240                                                   h_dex_cache,
    241                                                   h_class_loader,
    242                                                   referrer,
    243                                                   type);
    244   } else if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
    245     referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    246     // Check if the invoke type matches the class type.
    247     ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
    248     ObjPtr<mirror::ClassLoader> class_loader = referrer->GetClassLoader();
    249     if (CheckInvokeClassMismatch</* kThrow */ true>(dex_cache, type, method_idx, class_loader)) {
    250       DCHECK(Thread::Current()->IsExceptionPending());
    251       return nullptr;
    252     }
    253     // Check access.
    254     ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
    255     if (!referring_class->CheckResolvedMethodAccess(resolved_method->GetDeclaringClass(),
    256                                                     resolved_method,
    257                                                     dex_cache,
    258                                                     method_idx,
    259                                                     type)) {
    260       DCHECK(Thread::Current()->IsExceptionPending());
    261       return nullptr;
    262     }
    263     // Check if the invoke type matches the method type.
    264     if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
    265       ThrowIncompatibleClassChangeError(type,
    266                                         resolved_method->GetInvokeType(),
    267                                         resolved_method,
    268                                         referrer);
    269       return nullptr;
    270     }
    271   }
    272   // Note: We cannot check here to see whether we added the method to the cache. It
    273   //       might be an erroneous class, which results in it being hidden from us.
    274   return resolved_method;
    275 }
    276 
    277 inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
    278                                                   ArtMethod* referrer,
    279                                                   bool is_static) {
    280   ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
    281   ArtField* field = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
    282   if (field == nullptr) {
    283     field = LookupResolvedField(field_idx, dex_cache, referrer->GetClassLoader(), is_static);
    284   }
    285   return field;
    286 }
    287 
    288 inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
    289                                            ArtMethod* referrer,
    290                                            bool is_static) {
    291   Thread::PoisonObjectPointersIfDebug();
    292   ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
    293   ArtField* resolved_field =
    294       referrer->GetDexCache()->GetResolvedField(field_idx, image_pointer_size_);
    295   if (UNLIKELY(resolved_field == nullptr)) {
    296     StackHandleScope<2> hs(Thread::Current());
    297     Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
    298     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
    299     const DexFile& dex_file = *dex_cache->GetDexFile();
    300     resolved_field = ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
    301     // Note: We cannot check here to see whether we added the field to the cache. The type
    302     //       might be an erroneous class, which results in it being hidden from us.
    303   }
    304   return resolved_field;
    305 }
    306 
    307 inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root) {
    308   DCHECK(!class_roots_.IsNull());
    309   mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
    310   ObjPtr<mirror::Class> klass = class_roots->Get(class_root);
    311   DCHECK(klass != nullptr);
    312   return klass.Ptr();
    313 }
    314 
    315 template <class Visitor>
    316 inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
    317   Thread* const self = Thread::Current();
    318   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
    319   for (const ClassLoaderData& data : class_loaders_) {
    320     if (data.class_table != nullptr) {
    321       visitor(data.class_table);
    322     }
    323   }
    324 }
    325 
    326 }  // namespace art
    327 
    328 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
    329