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