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