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