1/* 2 * Copyright (C) 2012 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_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_ 18#define ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_ 19 20#include "compiler_driver.h" 21 22#include "art_field-inl.h" 23#include "art_method-inl.h" 24#include "class_linker-inl.h" 25#include "dex_compilation_unit.h" 26#include "mirror/class_loader.h" 27#include "mirror/dex_cache-inl.h" 28#include "scoped_thread_state_change.h" 29#include "handle_scope-inl.h" 30 31namespace art { 32 33inline mirror::DexCache* CompilerDriver::GetDexCache(const DexCompilationUnit* mUnit) { 34 return mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); 35} 36 37inline mirror::ClassLoader* CompilerDriver::GetClassLoader(ScopedObjectAccess& soa, 38 const DexCompilationUnit* mUnit) { 39 return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()); 40} 41 42inline mirror::Class* CompilerDriver::ResolveClass( 43 const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 44 Handle<mirror::ClassLoader> class_loader, uint16_t cls_index, 45 const DexCompilationUnit* mUnit) { 46 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); 47 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); 48 mirror::Class* cls = mUnit->GetClassLinker()->ResolveType( 49 *mUnit->GetDexFile(), cls_index, dex_cache, class_loader); 50 DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending()); 51 if (UNLIKELY(cls == nullptr)) { 52 // Clean up any exception left by type resolution. 53 soa.Self()->ClearException(); 54 } 55 return cls; 56} 57 58inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass( 59 const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 60 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) { 61 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); 62 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); 63 const DexFile::MethodId& referrer_method_id = 64 mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex()); 65 return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit); 66} 67 68inline ArtField* CompilerDriver::ResolveFieldWithDexFile( 69 const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 70 Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file, 71 uint32_t field_idx, bool is_static) { 72 DCHECK_EQ(dex_cache->GetDexFile(), dex_file); 73 ArtField* resolved_field = Runtime::Current()->GetClassLinker()->ResolveField( 74 *dex_file, field_idx, dex_cache, class_loader, is_static); 75 DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending()); 76 if (UNLIKELY(resolved_field == nullptr)) { 77 // Clean up any exception left by type resolution. 78 soa.Self()->ClearException(); 79 return nullptr; 80 } 81 if (UNLIKELY(resolved_field->IsStatic() != is_static)) { 82 // ClassLinker can return a field of the wrong kind directly from the DexCache. 83 // Silently return null on such incompatible class change. 84 return nullptr; 85 } 86 return resolved_field; 87} 88 89inline mirror::DexCache* CompilerDriver::FindDexCache(const DexFile* dex_file) { 90 return Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); 91} 92 93inline ArtField* CompilerDriver::ResolveField( 94 const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 95 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, 96 uint32_t field_idx, bool is_static) { 97 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); 98 return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx, 99 is_static); 100} 101 102inline void CompilerDriver::GetResolvedFieldDexFileLocation( 103 ArtField* resolved_field, const DexFile** declaring_dex_file, 104 uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) { 105 mirror::Class* declaring_class = resolved_field->GetDeclaringClass(); 106 *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile(); 107 *declaring_class_idx = declaring_class->GetDexTypeIndex(); 108 *declaring_field_idx = resolved_field->GetDexFieldIndex(); 109} 110 111inline bool CompilerDriver::IsFieldVolatile(ArtField* field) { 112 return field->IsVolatile(); 113} 114 115inline MemberOffset CompilerDriver::GetFieldOffset(ArtField* field) { 116 return field->GetOffset(); 117} 118 119inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField( 120 mirror::DexCache* dex_cache, mirror::Class* referrer_class, 121 ArtField* resolved_field, uint16_t field_idx) { 122 DCHECK(!resolved_field->IsStatic()); 123 mirror::Class* fields_class = resolved_field->GetDeclaringClass(); 124 bool fast_get = referrer_class != nullptr && 125 referrer_class->CanAccessResolvedField(fields_class, resolved_field, 126 dex_cache, field_idx); 127 bool fast_put = fast_get && (!resolved_field->IsFinal() || fields_class == referrer_class); 128 return std::make_pair(fast_get, fast_put); 129} 130 131template <typename ArtMember> 132inline bool CompilerDriver::CanAccessResolvedMember(mirror::Class* referrer_class ATTRIBUTE_UNUSED, 133 mirror::Class* access_to ATTRIBUTE_UNUSED, 134 ArtMember* member ATTRIBUTE_UNUSED, 135 mirror::DexCache* dex_cache ATTRIBUTE_UNUSED, 136 uint32_t field_idx ATTRIBUTE_UNUSED) { 137 // Not defined for ArtMember values other than ArtField or ArtMethod. 138 UNREACHABLE(); 139} 140 141template <> 142inline bool CompilerDriver::CanAccessResolvedMember<ArtField>(mirror::Class* referrer_class, 143 mirror::Class* access_to, 144 ArtField* field, 145 mirror::DexCache* dex_cache, 146 uint32_t field_idx) { 147 return referrer_class->CanAccessResolvedField(access_to, field, dex_cache, field_idx); 148} 149 150template <> 151inline bool CompilerDriver::CanAccessResolvedMember<ArtMethod>( 152 mirror::Class* referrer_class, 153 mirror::Class* access_to, 154 ArtMethod* method, 155 mirror::DexCache* dex_cache, 156 uint32_t field_idx) { 157 return referrer_class->CanAccessResolvedMethod(access_to, method, dex_cache, field_idx); 158} 159 160template <typename ArtMember> 161inline std::pair<bool, bool> CompilerDriver::IsClassOfStaticMemberAvailableToReferrer( 162 mirror::DexCache* dex_cache, 163 mirror::Class* referrer_class, 164 ArtMember* resolved_member, 165 uint16_t member_idx, 166 uint32_t* storage_index) { 167 DCHECK(resolved_member->IsStatic()); 168 if (LIKELY(referrer_class != nullptr)) { 169 mirror::Class* members_class = resolved_member->GetDeclaringClass(); 170 if (members_class == referrer_class) { 171 *storage_index = members_class->GetDexTypeIndex(); 172 return std::make_pair(true, true); 173 } 174 if (CanAccessResolvedMember<ArtMember>( 175 referrer_class, members_class, resolved_member, dex_cache, member_idx)) { 176 // We have the resolved member, we must make it into a index for the referrer 177 // in its static storage (which may fail if it doesn't have a slot for it) 178 // TODO: for images we can elide the static storage base null check 179 // if we know there's a non-null entry in the image 180 const DexFile* dex_file = dex_cache->GetDexFile(); 181 uint32_t storage_idx = DexFile::kDexNoIndex; 182 if (LIKELY(members_class->GetDexCache() == dex_cache)) { 183 // common case where the dex cache of both the referrer and the member are the same, 184 // no need to search the dex file 185 storage_idx = members_class->GetDexTypeIndex(); 186 } else { 187 // Search dex file for localized ssb index, may fail if member's class is a parent 188 // of the class mentioned in the dex file and there is no dex cache entry. 189 std::string temp; 190 const DexFile::StringId* string_id = 191 dex_file->FindStringId(resolved_member->GetDeclaringClass()->GetDescriptor(&temp)); 192 if (string_id != nullptr) { 193 const DexFile::TypeId* type_id = 194 dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id)); 195 if (type_id != nullptr) { 196 // medium path, needs check of static storage base being initialized 197 storage_idx = dex_file->GetIndexForTypeId(*type_id); 198 } 199 } 200 } 201 if (storage_idx != DexFile::kDexNoIndex) { 202 *storage_index = storage_idx; 203 return std::make_pair(true, !resolved_member->IsFinal()); 204 } 205 } 206 } 207 // Conservative defaults. 208 *storage_index = DexFile::kDexNoIndex; 209 return std::make_pair(false, false); 210} 211 212inline std::pair<bool, bool> CompilerDriver::IsFastStaticField( 213 mirror::DexCache* dex_cache, mirror::Class* referrer_class, 214 ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index) { 215 return IsClassOfStaticMemberAvailableToReferrer( 216 dex_cache, referrer_class, resolved_field, field_idx, storage_index); 217} 218 219inline bool CompilerDriver::IsClassOfStaticMethodAvailableToReferrer( 220 mirror::DexCache* dex_cache, mirror::Class* referrer_class, 221 ArtMethod* resolved_method, uint16_t method_idx, uint32_t* storage_index) { 222 std::pair<bool, bool> result = IsClassOfStaticMemberAvailableToReferrer( 223 dex_cache, referrer_class, resolved_method, method_idx, storage_index); 224 // Only the first member of `result` is meaningful, as there is no 225 // "write access" to a method. 226 return result.first; 227} 228 229inline bool CompilerDriver::IsStaticFieldInReferrerClass(mirror::Class* referrer_class, 230 ArtField* resolved_field) { 231 DCHECK(resolved_field->IsStatic()); 232 mirror::Class* fields_class = resolved_field->GetDeclaringClass(); 233 return referrer_class == fields_class; 234} 235 236inline bool CompilerDriver::CanAssumeClassIsInitialized(mirror::Class* klass) { 237 // Being loaded is a pre-requisite for being initialized but let's do the cheap check first. 238 // 239 // NOTE: When AOT compiling an app, we eagerly initialize app classes (and potentially their 240 // super classes in the boot image) but only those that have a trivial initialization, i.e. 241 // without <clinit>() or static values in the dex file for that class or any of its super 242 // classes. So while we could see the klass as initialized during AOT compilation and have 243 // it only loaded at runtime, the needed initialization would have to be trivial and 244 // unobservable from Java, so we may as well treat it as initialized. 245 if (!klass->IsInitialized()) { 246 return false; 247 } 248 return CanAssumeClassIsLoaded(klass); 249} 250 251inline bool CompilerDriver::CanReferrerAssumeClassIsInitialized(mirror::Class* referrer_class, 252 mirror::Class* klass) { 253 return (referrer_class != nullptr 254 && !referrer_class->IsInterface() 255 && referrer_class->IsSubClass(klass)) 256 || CanAssumeClassIsInitialized(klass); 257} 258 259inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referrer_class, 260 ArtField* resolved_field) { 261 DCHECK(resolved_field->IsStatic()); 262 mirror::Class* fields_class = resolved_field->GetDeclaringClass(); 263 return CanReferrerAssumeClassIsInitialized(referrer_class, fields_class); 264} 265 266inline ArtMethod* CompilerDriver::ResolveMethod( 267 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 268 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, 269 uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) { 270 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); 271 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); 272 ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod( 273 *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type); 274 DCHECK_EQ(resolved_method == nullptr, soa.Self()->IsExceptionPending()); 275 if (UNLIKELY(resolved_method == nullptr)) { 276 // Clean up any exception left by type resolution. 277 soa.Self()->ClearException(); 278 return nullptr; 279 } 280 if (check_incompatible_class_change && 281 UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) { 282 // Silently return null on incompatible class change. 283 return nullptr; 284 } 285 return resolved_method; 286} 287 288inline void CompilerDriver::GetResolvedMethodDexFileLocation( 289 ArtMethod* resolved_method, const DexFile** declaring_dex_file, 290 uint16_t* declaring_class_idx, uint16_t* declaring_method_idx) { 291 mirror::Class* declaring_class = resolved_method->GetDeclaringClass(); 292 *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile(); 293 *declaring_class_idx = declaring_class->GetDexTypeIndex(); 294 *declaring_method_idx = resolved_method->GetDexMethodIndex(); 295} 296 297inline uint16_t CompilerDriver::GetResolvedMethodVTableIndex( 298 ArtMethod* resolved_method, InvokeType type) { 299 if (type == kVirtual || type == kSuper) { 300 return resolved_method->GetMethodIndex(); 301 } else if (type == kInterface) { 302 return resolved_method->GetDexMethodIndex(); 303 } else { 304 return DexFile::kDexNoIndex16; 305 } 306} 307 308inline int CompilerDriver::IsFastInvoke( 309 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 310 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, 311 mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type, 312 MethodReference* target_method, const MethodReference* devirt_target, 313 uintptr_t* direct_code, uintptr_t* direct_method) { 314 // Don't try to fast-path if we don't understand the caller's class. 315 if (UNLIKELY(referrer_class == nullptr)) { 316 return 0; 317 } 318 mirror::Class* methods_class = resolved_method->GetDeclaringClass(); 319 if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_class, resolved_method, 320 dex_cache.Get(), 321 target_method->dex_method_index))) { 322 return 0; 323 } 324 // Sharpen a virtual call into a direct call when the target is known not to have been 325 // overridden (ie is final). 326 const bool same_dex_file = target_method->dex_file == mUnit->GetDexFile(); 327 bool can_sharpen_virtual_based_on_type = same_dex_file && 328 (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); 329 // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of 330 // the super class. 331 const size_t pointer_size = InstructionSetPointerSize(GetInstructionSet()); 332 bool can_sharpen_super_based_on_type = same_dex_file && (*invoke_type == kSuper) && 333 (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) && 334 resolved_method->GetMethodIndex() < methods_class->GetVTableLength() && 335 (methods_class->GetVTableEntry( 336 resolved_method->GetMethodIndex(), pointer_size) == resolved_method) && 337 !resolved_method->IsAbstract(); 338 339 if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) { 340 // Sharpen a virtual call into a direct call. The method_idx is into referrer's 341 // dex cache, check that this resolved method is where we expect it. 342 CHECK_EQ(target_method->dex_file, mUnit->GetDexFile()); 343 DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())); 344 CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod( 345 target_method->dex_method_index, pointer_size), 346 resolved_method) << PrettyMethod(resolved_method); 347 int stats_flags = kFlagMethodResolved; 348 GetCodeAndMethodForDirectCall(/*out*/invoke_type, 349 kDirect, // Sharp type 350 false, // The dex cache is guaranteed to be available 351 referrer_class, resolved_method, 352 /*out*/&stats_flags, 353 target_method, 354 /*out*/direct_code, 355 /*out*/direct_method); 356 DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method); 357 if (*invoke_type == kDirect) { 358 stats_flags |= kFlagsMethodResolvedVirtualMadeDirect; 359 } 360 return stats_flags; 361 } 362 363 if ((*invoke_type == kVirtual || *invoke_type == kInterface) && devirt_target != nullptr) { 364 // Post-verification callback recorded a more precise invoke target based on its type info. 365 ArtMethod* called_method; 366 ClassLinker* class_linker = mUnit->GetClassLinker(); 367 if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) { 368 called_method = class_linker->ResolveMethod( 369 *devirt_target->dex_file, devirt_target->dex_method_index, dex_cache, class_loader, 370 nullptr, kVirtual); 371 } else { 372 StackHandleScope<1> hs(soa.Self()); 373 auto target_dex_cache(hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file))); 374 called_method = class_linker->ResolveMethod( 375 *devirt_target->dex_file, devirt_target->dex_method_index, target_dex_cache, 376 class_loader, nullptr, kVirtual); 377 } 378 CHECK(called_method != nullptr); 379 CHECK(!called_method->IsAbstract()); 380 int stats_flags = kFlagMethodResolved; 381 GetCodeAndMethodForDirectCall(/*out*/invoke_type, 382 kDirect, // Sharp type 383 true, // The dex cache may not be available 384 referrer_class, called_method, 385 /*out*/&stats_flags, 386 target_method, 387 /*out*/direct_code, 388 /*out*/direct_method); 389 DCHECK_NE(*invoke_type, kSuper); 390 if (*invoke_type == kDirect) { 391 stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization; 392 } 393 return stats_flags; 394 } 395 396 if (UNLIKELY(*invoke_type == kSuper)) { 397 // Unsharpened super calls are suspicious so go slow-path. 398 return 0; 399 } 400 401 // Sharpening failed so generate a regular resolved method dispatch. 402 int stats_flags = kFlagMethodResolved; 403 GetCodeAndMethodForDirectCall(/*out*/invoke_type, 404 *invoke_type, // Sharp type 405 false, // The dex cache is guaranteed to be available 406 referrer_class, resolved_method, 407 /*out*/&stats_flags, 408 target_method, 409 /*out*/direct_code, 410 /*out*/direct_method); 411 return stats_flags; 412} 413 414inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_class, 415 ArtMethod* resolved_method) { 416 if (!resolved_method->IsStatic()) { 417 return true; 418 } 419 mirror::Class* methods_class = resolved_method->GetDeclaringClass(); 420 return CanReferrerAssumeClassIsInitialized(referrer_class, methods_class); 421} 422 423} // namespace art 424 425#endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_ 426