compiler_driver-inl.h revision 0e7f37de5bcebb413712eddd1831f30bd0818664
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