blob: 99fcc26aa5ffd1b200c0fae7b8aaf9d4a341eb6f [file] [log] [blame]
Vladimir Markobe0e5462014-02-26 11:24:15 +00001/*
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"
Mingyao Yang98d1cc82014-05-15 17:02:16 -070021
Vladimir Markobe0e5462014-02-26 11:24:15 +000022#include "dex/compiler_ir.h"
23#include "mirror/art_field.h"
24#include "mirror/art_field-inl.h"
Vladimir Markof096aad2014-01-23 15:51:58 +000025#include "mirror/art_method.h"
26#include "mirror/art_method-inl.h"
Vladimir Markobe0e5462014-02-26 11:24:15 +000027#include "mirror/class_loader.h"
28#include "mirror/dex_cache.h"
Vladimir Markof096aad2014-01-23 15:51:58 +000029#include "mirror/dex_cache-inl.h"
Vladimir Markobe0e5462014-02-26 11:24:15 +000030#include "mirror/art_field-inl.h"
31#include "scoped_thread_state_change.h"
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070032#include "handle_scope-inl.h"
Vladimir Markobe0e5462014-02-26 11:24:15 +000033
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(
Mathieu Chartier0cd81352014-05-22 16:48:55 -070046 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
47 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070048 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
49 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
Vladimir Markobe0e5462014-02-26 11:24:15 +000050 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(
Mathieu Chartier0cd81352014-05-22 16:48:55 -070063 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
64 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
Vladimir Markobe0e5462014-02-26 11:24:15 +000065 uint32_t field_idx, bool is_static) {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070066 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
67 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
Vladimir Markobe0e5462014-02-26 11:24:15 +000068 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.
Mathieu Chartier61c5ebc2014-06-05 17:42:53 -0700139 StackHandleScope<1> hs(Thread::Current());
Vladimir Markobe0e5462014-02-26 11:24:15 +0000140 const DexFile::StringId* string_id =
Mathieu Chartier61c5ebc2014-06-05 17:42:53 -0700141 dex_file->FindStringId(
142 FieldHelper(hs.NewHandle(resolved_field)).GetDeclaringClassDescriptor());
Vladimir Markobe0e5462014-02-26 11:24:15 +0000143 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
Vladimir Markof096aad2014-01-23 15:51:58 +0000170inline mirror::ArtMethod* CompilerDriver::ResolveMethod(
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700171 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
172 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
Vladimir Markof096aad2014-01-23 15:51:58 +0000173 uint32_t method_idx, InvokeType invoke_type) {
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700174 DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
175 DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
Vladimir Markof096aad2014-01-23 15:51:58 +0000176 mirror::ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod(
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700177 *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, NullHandle<mirror::ArtMethod>(),
178 invoke_type);
Vladimir Markof096aad2014-01-23 15:51:58 +0000179 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(
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700213 ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
214 Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
Vladimir Markof096aad2014-01-23 15:51:58 +0000215 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,
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700224 dex_cache.Get(),
Vladimir Markof096aad2014-01-23 15:51:58 +0000225 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->GetVTable()->GetLength() &&
238 (methods_class->GetVTable()->Get(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());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700244 DCHECK(dex_cache.Get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
Vladimir Markof096aad2014-01-23 15:51:58 +0000245 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,
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700263 devirt_target->dex_method_index, dex_cache,
264 class_loader, NullHandle<mirror::ArtMethod>(),
265 kVirtual);
Vladimir Markof096aad2014-01-23 15:51:58 +0000266 } else {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700267 StackHandleScope<1> hs(soa.Self());
268 Handle<mirror::DexCache> target_dex_cache(
269 hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file)));
Vladimir Markof096aad2014-01-23 15:51:58 +0000270 called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
271 devirt_target->dex_method_index,
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700272 target_dex_cache, class_loader,
273 NullHandle<mirror::ArtMethod>(), kVirtual);
Vladimir Markof096aad2014-01-23 15:51:58 +0000274 }
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
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000299inline 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
Vladimir Markobe0e5462014-02-26 11:24:15 +0000309} // namespace art
310
311#endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_