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 "dex/compiler_ir.h" 23 #include "field_helper.h" 24 #include "mirror/art_field-inl.h" 25 #include "mirror/art_method-inl.h" 26 #include "mirror/class_loader.h" 27 #include "mirror/dex_cache-inl.h" 28 #include "mirror/art_field-inl.h" 29 #include "scoped_thread_state_change.h" 30 #include "handle_scope-inl.h" 31 32 namespace art { 33 34 inline mirror::DexCache* CompilerDriver::GetDexCache(const DexCompilationUnit* mUnit) { 35 return mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); 36 } 37 38 inline mirror::ClassLoader* CompilerDriver::GetClassLoader(ScopedObjectAccess& soa, 39 const DexCompilationUnit* mUnit) { 40 return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()); 41 } 42 43 inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass( 44 const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 45 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) { 46 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); 47 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); 48 const DexFile::MethodId& referrer_method_id = 49 mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex()); 50 mirror::Class* referrer_class = mUnit->GetClassLinker()->ResolveType( 51 *mUnit->GetDexFile(), referrer_method_id.class_idx_, dex_cache, class_loader); 52 DCHECK_EQ(referrer_class == nullptr, soa.Self()->IsExceptionPending()); 53 if (UNLIKELY(referrer_class == nullptr)) { 54 // Clean up any exception left by type resolution. 55 soa.Self()->ClearException(); 56 } 57 return referrer_class; 58 } 59 60 inline mirror::ArtField* CompilerDriver::ResolveField( 61 const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 62 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, 63 uint32_t field_idx, bool is_static) { 64 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); 65 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); 66 mirror::ArtField* resolved_field = mUnit->GetClassLinker()->ResolveField( 67 *mUnit->GetDexFile(), field_idx, dex_cache, class_loader, is_static); 68 DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending()); 69 if (UNLIKELY(resolved_field == nullptr)) { 70 // Clean up any exception left by type resolution. 71 soa.Self()->ClearException(); 72 return nullptr; 73 } 74 if (UNLIKELY(resolved_field->IsStatic() != is_static)) { 75 // ClassLinker can return a field of the wrong kind directly from the DexCache. 76 // Silently return nullptr on such incompatible class change. 77 return nullptr; 78 } 79 return resolved_field; 80 } 81 82 inline void CompilerDriver::GetResolvedFieldDexFileLocation( 83 mirror::ArtField* resolved_field, const DexFile** declaring_dex_file, 84 uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) { 85 mirror::Class* declaring_class = resolved_field->GetDeclaringClass(); 86 *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile(); 87 *declaring_class_idx = declaring_class->GetDexTypeIndex(); 88 *declaring_field_idx = resolved_field->GetDexFieldIndex(); 89 } 90 91 inline bool CompilerDriver::IsFieldVolatile(mirror::ArtField* field) { 92 return field->IsVolatile(); 93 } 94 95 inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField( 96 mirror::DexCache* dex_cache, mirror::Class* referrer_class, 97 mirror::ArtField* resolved_field, uint16_t field_idx) { 98 DCHECK(!resolved_field->IsStatic()); 99 mirror::Class* fields_class = resolved_field->GetDeclaringClass(); 100 bool fast_get = referrer_class != nullptr && 101 referrer_class->CanAccessResolvedField(fields_class, resolved_field, 102 dex_cache, field_idx); 103 bool fast_put = fast_get && (!resolved_field->IsFinal() || fields_class == referrer_class); 104 return std::make_pair(fast_get, fast_put); 105 } 106 107 inline std::pair<bool, bool> CompilerDriver::IsFastStaticField( 108 mirror::DexCache* dex_cache, mirror::Class* referrer_class, 109 mirror::ArtField* resolved_field, uint16_t field_idx, MemberOffset* field_offset, 110 uint32_t* storage_index, bool* is_referrers_class, bool* is_initialized) { 111 DCHECK(resolved_field->IsStatic()); 112 if (LIKELY(referrer_class != nullptr)) { 113 mirror::Class* fields_class = resolved_field->GetDeclaringClass(); 114 if (fields_class == referrer_class) { 115 *field_offset = resolved_field->GetOffset(); 116 *storage_index = fields_class->GetDexTypeIndex(); 117 *is_referrers_class = true; // implies no worrying about class initialization 118 *is_initialized = true; 119 return std::make_pair(true, true); 120 } 121 if (referrer_class->CanAccessResolvedField(fields_class, resolved_field, 122 dex_cache, field_idx)) { 123 // We have the resolved field, we must make it into a index for the referrer 124 // in its static storage (which may fail if it doesn't have a slot for it) 125 // TODO: for images we can elide the static storage base null check 126 // if we know there's a non-null entry in the image 127 const DexFile* dex_file = dex_cache->GetDexFile(); 128 uint32_t storage_idx = DexFile::kDexNoIndex; 129 if (LIKELY(fields_class->GetDexCache() == dex_cache)) { 130 // common case where the dex cache of both the referrer and the field are the same, 131 // no need to search the dex file 132 storage_idx = fields_class->GetDexTypeIndex(); 133 } else { 134 // Search dex file for localized ssb index, may fail if field's class is a parent 135 // of the class mentioned in the dex file and there is no dex cache entry. 136 StackHandleScope<1> hs(Thread::Current()); 137 const DexFile::StringId* string_id = 138 dex_file->FindStringId( 139 FieldHelper(hs.NewHandle(resolved_field)).GetDeclaringClassDescriptor()); 140 if (string_id != nullptr) { 141 const DexFile::TypeId* type_id = 142 dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id)); 143 if (type_id != nullptr) { 144 // medium path, needs check of static storage base being initialized 145 storage_idx = dex_file->GetIndexForTypeId(*type_id); 146 } 147 } 148 } 149 if (storage_idx != DexFile::kDexNoIndex) { 150 *field_offset = resolved_field->GetOffset(); 151 *storage_index = storage_idx; 152 *is_referrers_class = false; 153 *is_initialized = fields_class->IsInitialized() && 154 CanAssumeTypeIsPresentInDexCache(*dex_file, storage_idx); 155 return std::make_pair(true, !resolved_field->IsFinal()); 156 } 157 } 158 } 159 // Conservative defaults. 160 *field_offset = MemberOffset(0u); 161 *storage_index = DexFile::kDexNoIndex; 162 *is_referrers_class = false; 163 *is_initialized = false; 164 return std::make_pair(false, false); 165 } 166 167 inline mirror::ArtMethod* CompilerDriver::ResolveMethod( 168 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 169 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, 170 uint32_t method_idx, InvokeType invoke_type) { 171 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); 172 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); 173 mirror::ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod( 174 *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, NullHandle<mirror::ArtMethod>(), 175 invoke_type); 176 DCHECK_EQ(resolved_method == nullptr, soa.Self()->IsExceptionPending()); 177 if (UNLIKELY(resolved_method == nullptr)) { 178 // Clean up any exception left by type resolution. 179 soa.Self()->ClearException(); 180 return nullptr; 181 } 182 if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) { 183 // Silently return nullptr on incompatible class change. 184 return nullptr; 185 } 186 return resolved_method; 187 } 188 189 inline void CompilerDriver::GetResolvedMethodDexFileLocation( 190 mirror::ArtMethod* resolved_method, const DexFile** declaring_dex_file, 191 uint16_t* declaring_class_idx, uint16_t* declaring_method_idx) { 192 mirror::Class* declaring_class = resolved_method->GetDeclaringClass(); 193 *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile(); 194 *declaring_class_idx = declaring_class->GetDexTypeIndex(); 195 *declaring_method_idx = resolved_method->GetDexMethodIndex(); 196 } 197 198 inline uint16_t CompilerDriver::GetResolvedMethodVTableIndex( 199 mirror::ArtMethod* resolved_method, InvokeType type) { 200 if (type == kVirtual || type == kSuper) { 201 return resolved_method->GetMethodIndex(); 202 } else if (type == kInterface) { 203 return resolved_method->GetDexMethodIndex(); 204 } else { 205 return DexFile::kDexNoIndex16; 206 } 207 } 208 209 inline int CompilerDriver::IsFastInvoke( 210 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, 211 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, 212 mirror::Class* referrer_class, mirror::ArtMethod* resolved_method, InvokeType* invoke_type, 213 MethodReference* target_method, const MethodReference* devirt_target, 214 uintptr_t* direct_code, uintptr_t* direct_method) { 215 // Don't try to fast-path if we don't understand the caller's class. 216 if (UNLIKELY(referrer_class == nullptr)) { 217 return 0; 218 } 219 mirror::Class* methods_class = resolved_method->GetDeclaringClass(); 220 if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_class, resolved_method, 221 dex_cache.Get(), 222 target_method->dex_method_index))) { 223 return 0; 224 } 225 226 // Sharpen a virtual call into a direct call when the target is known not to have been 227 // overridden (ie is final). 228 bool can_sharpen_virtual_based_on_type = 229 (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); 230 // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of 231 // the super class. 232 bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) && 233 (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) && 234 resolved_method->GetMethodIndex() < methods_class->GetVTableLength() && 235 (methods_class->GetVTableEntry(resolved_method->GetMethodIndex()) == resolved_method); 236 237 if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) { 238 // Sharpen a virtual call into a direct call. The method_idx is into referrer's 239 // dex cache, check that this resolved method is where we expect it. 240 CHECK(target_method->dex_file == mUnit->GetDexFile()); 241 DCHECK(dex_cache.Get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())); 242 CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) == 243 resolved_method) << PrettyMethod(resolved_method); 244 int stats_flags = kFlagMethodResolved; 245 GetCodeAndMethodForDirectCall(invoke_type, kDirect, false, referrer_class, resolved_method, 246 &stats_flags, target_method, direct_code, direct_method); 247 DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method); 248 if (*invoke_type == kDirect) { 249 stats_flags |= kFlagsMethodResolvedVirtualMadeDirect; 250 } 251 return stats_flags; 252 } 253 254 if ((*invoke_type == kVirtual || *invoke_type == kInterface) && devirt_target != nullptr) { 255 // Post-verification callback recorded a more precise invoke target based on its type info. 256 mirror::ArtMethod* called_method; 257 ClassLinker* class_linker = mUnit->GetClassLinker(); 258 if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) { 259 called_method = class_linker->ResolveMethod(*devirt_target->dex_file, 260 devirt_target->dex_method_index, dex_cache, 261 class_loader, NullHandle<mirror::ArtMethod>(), 262 kVirtual); 263 } else { 264 StackHandleScope<1> hs(soa.Self()); 265 Handle<mirror::DexCache> target_dex_cache( 266 hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file))); 267 called_method = class_linker->ResolveMethod(*devirt_target->dex_file, 268 devirt_target->dex_method_index, 269 target_dex_cache, class_loader, 270 NullHandle<mirror::ArtMethod>(), kVirtual); 271 } 272 CHECK(called_method != NULL); 273 CHECK(!called_method->IsAbstract()); 274 int stats_flags = kFlagMethodResolved; 275 GetCodeAndMethodForDirectCall(invoke_type, kDirect, true, referrer_class, called_method, 276 &stats_flags, target_method, direct_code, direct_method); 277 DCHECK_NE(*invoke_type, kSuper); 278 if (*invoke_type == kDirect) { 279 stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization; 280 } 281 return stats_flags; 282 } 283 284 if (UNLIKELY(*invoke_type == kSuper)) { 285 // Unsharpened super calls are suspicious so go slow-path. 286 return 0; 287 } 288 289 // Sharpening failed so generate a regular resolved method dispatch. 290 int stats_flags = kFlagMethodResolved; 291 GetCodeAndMethodForDirectCall(invoke_type, *invoke_type, false, referrer_class, resolved_method, 292 &stats_flags, target_method, direct_code, direct_method); 293 return stats_flags; 294 } 295 296 inline bool CompilerDriver::NeedsClassInitialization(mirror::Class* referrer_class, 297 mirror::ArtMethod* resolved_method) { 298 if (!resolved_method->IsStatic()) { 299 return false; 300 } 301 mirror::Class* methods_class = resolved_method->GetDeclaringClass(); 302 // NOTE: Unlike in IsFastStaticField(), we don't check CanAssumeTypeIsPresentInDexCache() here. 303 return methods_class != referrer_class && !methods_class->IsInitialized(); 304 } 305 306 } // namespace art 307 308 #endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_ 309