Home | History | Annotate | Download | only in driver
      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       !resolved_method->IsAbstract();
    237 
    238   if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) {
    239     // Sharpen a virtual call into a direct call. The method_idx is into referrer's
    240     // dex cache, check that this resolved method is where we expect it.
    241     CHECK(target_method->dex_file == mUnit->GetDexFile());
    242     DCHECK(dex_cache.Get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
    243     CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) ==
    244         resolved_method) << PrettyMethod(resolved_method);
    245     int stats_flags = kFlagMethodResolved;
    246     GetCodeAndMethodForDirectCall(/*out*/invoke_type,
    247                                   kDirect,  // Sharp type
    248                                   false,    // The dex cache is guaranteed to be available
    249                                   referrer_class, resolved_method,
    250                                   /*out*/&stats_flags,
    251                                   target_method,
    252                                   /*out*/direct_code,
    253                                   /*out*/direct_method);
    254     DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method);
    255     if (*invoke_type == kDirect) {
    256       stats_flags |= kFlagsMethodResolvedVirtualMadeDirect;
    257     }
    258     return stats_flags;
    259   }
    260 
    261   if ((*invoke_type == kVirtual || *invoke_type == kInterface) && devirt_target != nullptr) {
    262     // Post-verification callback recorded a more precise invoke target based on its type info.
    263     mirror::ArtMethod* called_method;
    264     ClassLinker* class_linker = mUnit->GetClassLinker();
    265     if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) {
    266       called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
    267                                                   devirt_target->dex_method_index, dex_cache,
    268                                                   class_loader, NullHandle<mirror::ArtMethod>(),
    269                                                   kVirtual);
    270     } else {
    271       StackHandleScope<1> hs(soa.Self());
    272       Handle<mirror::DexCache> target_dex_cache(
    273           hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file)));
    274       called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
    275                                                   devirt_target->dex_method_index,
    276                                                   target_dex_cache, class_loader,
    277                                                   NullHandle<mirror::ArtMethod>(), kVirtual);
    278     }
    279     CHECK(called_method != NULL);
    280     CHECK(!called_method->IsAbstract());
    281     int stats_flags = kFlagMethodResolved;
    282     GetCodeAndMethodForDirectCall(/*out*/invoke_type,
    283                                   kDirect,  // Sharp type
    284                                   true,     // The dex cache may not be available
    285                                   referrer_class, called_method,
    286                                   /*out*/&stats_flags,
    287                                   target_method,
    288                                   /*out*/direct_code,
    289                                   /*out*/direct_method);
    290     DCHECK_NE(*invoke_type, kSuper);
    291     if (*invoke_type == kDirect) {
    292       stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization;
    293     }
    294     return stats_flags;
    295   }
    296 
    297   if (UNLIKELY(*invoke_type == kSuper)) {
    298     // Unsharpened super calls are suspicious so go slow-path.
    299     return 0;
    300   }
    301 
    302   // Sharpening failed so generate a regular resolved method dispatch.
    303   int stats_flags = kFlagMethodResolved;
    304   GetCodeAndMethodForDirectCall(/*out*/invoke_type,
    305                                 *invoke_type,  // Sharp type
    306                                 false,         // The dex cache is guaranteed to be available
    307                                 referrer_class, resolved_method,
    308                                 /*out*/&stats_flags,
    309                                 target_method,
    310                                 /*out*/direct_code,
    311                                 /*out*/direct_method);
    312   return stats_flags;
    313 }
    314 
    315 inline bool CompilerDriver::NeedsClassInitialization(mirror::Class* referrer_class,
    316                                                      mirror::ArtMethod* resolved_method) {
    317   if (!resolved_method->IsStatic()) {
    318     return false;
    319   }
    320   mirror::Class* methods_class = resolved_method->GetDeclaringClass();
    321   // NOTE: Unlike in IsFastStaticField(), we don't check CanAssumeTypeIsPresentInDexCache() here.
    322   return methods_class != referrer_class && !methods_class->IsInitialized();
    323 }
    324 
    325 }  // namespace art
    326 
    327 #endif  // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
    328