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 "art_field-inl.h"
23#include "art_method-inl.h"
24#include "class_linker-inl.h"
25#include "dex_compilation_unit.h"
26#include "mirror/class_loader.h"
27#include "mirror/dex_cache-inl.h"
28#include "scoped_thread_state_change.h"
29#include "handle_scope-inl.h"
30
31namespace art {
32
33inline mirror::DexCache* CompilerDriver::GetDexCache(const DexCompilationUnit* mUnit) {
34  return mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
35}
36
37inline mirror::ClassLoader* CompilerDriver::GetClassLoader(ScopedObjectAccess& soa,
38                                                           const DexCompilationUnit* mUnit) {
39  return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
40}
41
42inline mirror::Class* CompilerDriver::ResolveClass(
43    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
44    Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
45    const DexCompilationUnit* mUnit) {
46  DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
47  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
48  mirror::Class* cls = mUnit->GetClassLinker()->ResolveType(
49      *mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
50  DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
51  if (UNLIKELY(cls == nullptr)) {
52    // Clean up any exception left by type resolution.
53    soa.Self()->ClearException();
54  }
55  return cls;
56}
57
58inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
59    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
60    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
61  DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
62  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
63  const DexFile::MethodId& referrer_method_id =
64      mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
65  return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit);
66}
67
68inline ArtField* CompilerDriver::ResolveFieldWithDexFile(
69    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
70    Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file,
71    uint32_t field_idx, bool is_static) {
72  DCHECK_EQ(dex_cache->GetDexFile(), dex_file);
73  ArtField* resolved_field = Runtime::Current()->GetClassLinker()->ResolveField(
74      *dex_file, field_idx, dex_cache, class_loader, is_static);
75  DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending());
76  if (UNLIKELY(resolved_field == nullptr)) {
77    // Clean up any exception left by type resolution.
78    soa.Self()->ClearException();
79    return nullptr;
80  }
81  if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
82    // ClassLinker can return a field of the wrong kind directly from the DexCache.
83    // Silently return null on such incompatible class change.
84    return nullptr;
85  }
86  return resolved_field;
87}
88
89inline mirror::DexCache* CompilerDriver::FindDexCache(const DexFile* dex_file) {
90  return Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file);
91}
92
93inline ArtField* CompilerDriver::ResolveField(
94    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
95    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
96    uint32_t field_idx, bool is_static) {
97  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
98  return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx,
99                                 is_static);
100}
101
102inline void CompilerDriver::GetResolvedFieldDexFileLocation(
103    ArtField* resolved_field, const DexFile** declaring_dex_file,
104    uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) {
105  mirror::Class* declaring_class = resolved_field->GetDeclaringClass();
106  *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile();
107  *declaring_class_idx = declaring_class->GetDexTypeIndex();
108  *declaring_field_idx = resolved_field->GetDexFieldIndex();
109}
110
111inline bool CompilerDriver::IsFieldVolatile(ArtField* field) {
112  return field->IsVolatile();
113}
114
115inline MemberOffset CompilerDriver::GetFieldOffset(ArtField* field) {
116  return field->GetOffset();
117}
118
119inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
120    mirror::DexCache* dex_cache, mirror::Class* referrer_class,
121    ArtField* resolved_field, uint16_t field_idx) {
122  DCHECK(!resolved_field->IsStatic());
123  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
124  bool fast_get = referrer_class != nullptr &&
125      referrer_class->CanAccessResolvedField(fields_class, resolved_field,
126                                             dex_cache, field_idx);
127  bool fast_put = fast_get && (!resolved_field->IsFinal() || fields_class == referrer_class);
128  return std::make_pair(fast_get, fast_put);
129}
130
131template <typename ArtMember>
132inline bool CompilerDriver::CanAccessResolvedMember(mirror::Class* referrer_class ATTRIBUTE_UNUSED,
133                                                    mirror::Class* access_to ATTRIBUTE_UNUSED,
134                                                    ArtMember* member ATTRIBUTE_UNUSED,
135                                                    mirror::DexCache* dex_cache ATTRIBUTE_UNUSED,
136                                                    uint32_t field_idx ATTRIBUTE_UNUSED) {
137  // Not defined for ArtMember values other than ArtField or ArtMethod.
138  UNREACHABLE();
139}
140
141template <>
142inline bool CompilerDriver::CanAccessResolvedMember<ArtField>(mirror::Class* referrer_class,
143                                                              mirror::Class* access_to,
144                                                              ArtField* field,
145                                                              mirror::DexCache* dex_cache,
146                                                              uint32_t field_idx) {
147  return referrer_class->CanAccessResolvedField(access_to, field, dex_cache, field_idx);
148}
149
150template <>
151inline bool CompilerDriver::CanAccessResolvedMember<ArtMethod>(
152    mirror::Class* referrer_class,
153    mirror::Class* access_to,
154    ArtMethod* method,
155    mirror::DexCache* dex_cache,
156    uint32_t field_idx) {
157  return referrer_class->CanAccessResolvedMethod(access_to, method, dex_cache, field_idx);
158}
159
160template <typename ArtMember>
161inline std::pair<bool, bool> CompilerDriver::IsClassOfStaticMemberAvailableToReferrer(
162    mirror::DexCache* dex_cache,
163    mirror::Class* referrer_class,
164    ArtMember* resolved_member,
165    uint16_t member_idx,
166    uint32_t* storage_index) {
167  DCHECK(resolved_member->IsStatic());
168  if (LIKELY(referrer_class != nullptr)) {
169    mirror::Class* members_class = resolved_member->GetDeclaringClass();
170    if (members_class == referrer_class) {
171      *storage_index = members_class->GetDexTypeIndex();
172      return std::make_pair(true, true);
173    }
174    if (CanAccessResolvedMember<ArtMember>(
175            referrer_class, members_class, resolved_member, dex_cache, member_idx)) {
176      // We have the resolved member, we must make it into a index for the referrer
177      // in its static storage (which may fail if it doesn't have a slot for it)
178      // TODO: for images we can elide the static storage base null check
179      // if we know there's a non-null entry in the image
180      const DexFile* dex_file = dex_cache->GetDexFile();
181      uint32_t storage_idx = DexFile::kDexNoIndex;
182      if (LIKELY(members_class->GetDexCache() == dex_cache)) {
183        // common case where the dex cache of both the referrer and the member are the same,
184        // no need to search the dex file
185        storage_idx = members_class->GetDexTypeIndex();
186      } else {
187        // Search dex file for localized ssb index, may fail if member's class is a parent
188        // of the class mentioned in the dex file and there is no dex cache entry.
189        std::string temp;
190        const DexFile::StringId* string_id =
191            dex_file->FindStringId(resolved_member->GetDeclaringClass()->GetDescriptor(&temp));
192        if (string_id != nullptr) {
193          const DexFile::TypeId* type_id =
194             dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
195          if (type_id != nullptr) {
196            // medium path, needs check of static storage base being initialized
197            storage_idx = dex_file->GetIndexForTypeId(*type_id);
198          }
199        }
200      }
201      if (storage_idx != DexFile::kDexNoIndex) {
202        *storage_index = storage_idx;
203        return std::make_pair(true, !resolved_member->IsFinal());
204      }
205    }
206  }
207  // Conservative defaults.
208  *storage_index = DexFile::kDexNoIndex;
209  return std::make_pair(false, false);
210}
211
212inline std::pair<bool, bool> CompilerDriver::IsFastStaticField(
213    mirror::DexCache* dex_cache, mirror::Class* referrer_class,
214    ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index) {
215  return IsClassOfStaticMemberAvailableToReferrer(
216      dex_cache, referrer_class, resolved_field, field_idx, storage_index);
217}
218
219inline bool CompilerDriver::IsClassOfStaticMethodAvailableToReferrer(
220    mirror::DexCache* dex_cache, mirror::Class* referrer_class,
221    ArtMethod* resolved_method, uint16_t method_idx, uint32_t* storage_index) {
222  std::pair<bool, bool> result = IsClassOfStaticMemberAvailableToReferrer(
223      dex_cache, referrer_class, resolved_method, method_idx, storage_index);
224  // Only the first member of `result` is meaningful, as there is no
225  // "write access" to a method.
226  return result.first;
227}
228
229inline bool CompilerDriver::IsStaticFieldInReferrerClass(mirror::Class* referrer_class,
230                                                         ArtField* resolved_field) {
231  DCHECK(resolved_field->IsStatic());
232  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
233  return referrer_class == fields_class;
234}
235
236inline bool CompilerDriver::CanAssumeClassIsInitialized(mirror::Class* klass) {
237  // Being loaded is a pre-requisite for being initialized but let's do the cheap check first.
238  //
239  // NOTE: When AOT compiling an app, we eagerly initialize app classes (and potentially their
240  // super classes in the boot image) but only those that have a trivial initialization, i.e.
241  // without <clinit>() or static values in the dex file for that class or any of its super
242  // classes. So while we could see the klass as initialized during AOT compilation and have
243  // it only loaded at runtime, the needed initialization would have to be trivial and
244  // unobservable from Java, so we may as well treat it as initialized.
245  if (!klass->IsInitialized()) {
246    return false;
247  }
248  return CanAssumeClassIsLoaded(klass);
249}
250
251inline bool CompilerDriver::CanReferrerAssumeClassIsInitialized(mirror::Class* referrer_class,
252                                                                mirror::Class* klass) {
253  return (referrer_class != nullptr
254          && !referrer_class->IsInterface()
255          && referrer_class->IsSubClass(klass))
256      || CanAssumeClassIsInitialized(klass);
257}
258
259inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referrer_class,
260                                                           ArtField* resolved_field) {
261  DCHECK(resolved_field->IsStatic());
262  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
263  return CanReferrerAssumeClassIsInitialized(referrer_class, fields_class);
264}
265
266inline ArtMethod* CompilerDriver::ResolveMethod(
267    ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
268    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
269    uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) {
270  DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
271  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
272  ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod(
273      *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type);
274  DCHECK_EQ(resolved_method == nullptr, soa.Self()->IsExceptionPending());
275  if (UNLIKELY(resolved_method == nullptr)) {
276    // Clean up any exception left by type resolution.
277    soa.Self()->ClearException();
278    return nullptr;
279  }
280  if (check_incompatible_class_change &&
281      UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) {
282    // Silently return null on incompatible class change.
283    return nullptr;
284  }
285  return resolved_method;
286}
287
288inline void CompilerDriver::GetResolvedMethodDexFileLocation(
289    ArtMethod* resolved_method, const DexFile** declaring_dex_file,
290    uint16_t* declaring_class_idx, uint16_t* declaring_method_idx) {
291  mirror::Class* declaring_class = resolved_method->GetDeclaringClass();
292  *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile();
293  *declaring_class_idx = declaring_class->GetDexTypeIndex();
294  *declaring_method_idx = resolved_method->GetDexMethodIndex();
295}
296
297inline uint16_t CompilerDriver::GetResolvedMethodVTableIndex(
298    ArtMethod* resolved_method, InvokeType type) {
299  if (type == kVirtual || type == kSuper) {
300    return resolved_method->GetMethodIndex();
301  } else if (type == kInterface) {
302    return resolved_method->GetDexMethodIndex();
303  } else {
304    return DexFile::kDexNoIndex16;
305  }
306}
307
308inline int CompilerDriver::IsFastInvoke(
309    ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
310    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
311    mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type,
312    MethodReference* target_method, const MethodReference* devirt_target,
313    uintptr_t* direct_code, uintptr_t* direct_method) {
314  // Don't try to fast-path if we don't understand the caller's class.
315  if (UNLIKELY(referrer_class == nullptr)) {
316    return 0;
317  }
318  mirror::Class* methods_class = resolved_method->GetDeclaringClass();
319  if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_class, resolved_method,
320                                                        dex_cache.Get(),
321                                                        target_method->dex_method_index))) {
322    return 0;
323  }
324  // Sharpen a virtual call into a direct call when the target is known not to have been
325  // overridden (ie is final).
326  const bool same_dex_file = target_method->dex_file == mUnit->GetDexFile();
327  bool can_sharpen_virtual_based_on_type = same_dex_file &&
328      (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
329  // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
330  // the super class.
331  const size_t pointer_size = InstructionSetPointerSize(GetInstructionSet());
332  bool can_sharpen_super_based_on_type = same_dex_file && (*invoke_type == kSuper) &&
333      (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
334      resolved_method->GetMethodIndex() < methods_class->GetVTableLength() &&
335      (methods_class->GetVTableEntry(
336          resolved_method->GetMethodIndex(), pointer_size) == resolved_method) &&
337      !resolved_method->IsAbstract();
338
339  if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) {
340    // Sharpen a virtual call into a direct call. The method_idx is into referrer's
341    // dex cache, check that this resolved method is where we expect it.
342    CHECK_EQ(target_method->dex_file, mUnit->GetDexFile());
343    DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
344    CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod(
345        target_method->dex_method_index, pointer_size),
346             resolved_method) << PrettyMethod(resolved_method);
347    int stats_flags = kFlagMethodResolved;
348    GetCodeAndMethodForDirectCall(/*out*/invoke_type,
349                                  kDirect,  // Sharp type
350                                  false,    // The dex cache is guaranteed to be available
351                                  referrer_class, resolved_method,
352                                  /*out*/&stats_flags,
353                                  target_method,
354                                  /*out*/direct_code,
355                                  /*out*/direct_method);
356    DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method);
357    if (*invoke_type == kDirect) {
358      stats_flags |= kFlagsMethodResolvedVirtualMadeDirect;
359    }
360    return stats_flags;
361  }
362
363  if ((*invoke_type == kVirtual || *invoke_type == kInterface) && devirt_target != nullptr) {
364    // Post-verification callback recorded a more precise invoke target based on its type info.
365    ArtMethod* called_method;
366    ClassLinker* class_linker = mUnit->GetClassLinker();
367    if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) {
368      called_method = class_linker->ResolveMethod(
369          *devirt_target->dex_file, devirt_target->dex_method_index, dex_cache, class_loader,
370          nullptr, kVirtual);
371    } else {
372      StackHandleScope<1> hs(soa.Self());
373      auto target_dex_cache(hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file)));
374      called_method = class_linker->ResolveMethod(
375          *devirt_target->dex_file, devirt_target->dex_method_index, target_dex_cache,
376          class_loader, nullptr, kVirtual);
377    }
378    CHECK(called_method != nullptr);
379    CHECK(!called_method->IsAbstract());
380    int stats_flags = kFlagMethodResolved;
381    GetCodeAndMethodForDirectCall(/*out*/invoke_type,
382                                  kDirect,  // Sharp type
383                                  true,     // The dex cache may not be available
384                                  referrer_class, called_method,
385                                  /*out*/&stats_flags,
386                                  target_method,
387                                  /*out*/direct_code,
388                                  /*out*/direct_method);
389    DCHECK_NE(*invoke_type, kSuper);
390    if (*invoke_type == kDirect) {
391      stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization;
392    }
393    return stats_flags;
394  }
395
396  if (UNLIKELY(*invoke_type == kSuper)) {
397    // Unsharpened super calls are suspicious so go slow-path.
398    return 0;
399  }
400
401  // Sharpening failed so generate a regular resolved method dispatch.
402  int stats_flags = kFlagMethodResolved;
403  GetCodeAndMethodForDirectCall(/*out*/invoke_type,
404                                *invoke_type,  // Sharp type
405                                false,         // The dex cache is guaranteed to be available
406                                referrer_class, resolved_method,
407                                /*out*/&stats_flags,
408                                target_method,
409                                /*out*/direct_code,
410                                /*out*/direct_method);
411  return stats_flags;
412}
413
414inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_class,
415                                                      ArtMethod* resolved_method) {
416  if (!resolved_method->IsStatic()) {
417    return true;
418  }
419  mirror::Class* methods_class = resolved_method->GetDeclaringClass();
420  return CanReferrerAssumeClassIsInitialized(referrer_class, methods_class);
421}
422
423}  // namespace art
424
425#endif  // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
426