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