1 /*
2 * Copyright (C) 2014 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 #include "inliner.h"
18
19 #include "art_method-inl.h"
20 #include "base/logging.h"
21 #include "base/pointer_size.h"
22 #include "builder.h"
23 #include "class_linker.h"
24 #include "class_root-inl.h"
25 #include "compiler_callbacks.h"
26 #include "constant_folding.h"
27 #include "data_type-inl.h"
28 #include "dead_code_elimination.h"
29 #include "dex/inline_method_analyser.h"
30 #include "driver/compiler_options.h"
31 #include "driver/dex_compilation_unit.h"
32 #include "handle_cache-inl.h"
33 #include "instruction_simplifier.h"
34 #include "intrinsics.h"
35 #include "jit/jit.h"
36 #include "jit/jit_code_cache.h"
37 #include "mirror/class_loader.h"
38 #include "mirror/dex_cache.h"
39 #include "mirror/object_array-alloc-inl.h"
40 #include "mirror/object_array-inl.h"
41 #include "nodes.h"
42 #include "profiling_info_builder.h"
43 #include "reference_type_propagation.h"
44 #include "register_allocator_linear_scan.h"
45 #include "scoped_thread_state_change-inl.h"
46 #include "sharpening.h"
47 #include "ssa_builder.h"
48 #include "ssa_phi_elimination.h"
49 #include "thread.h"
50 #include "verifier/verifier_compiler_binding.h"
51
52 namespace art HIDDEN {
53
54 // Instruction limit to control memory.
55 static constexpr size_t kMaximumNumberOfTotalInstructions = 1024;
56
57 // Maximum number of instructions for considering a method small,
58 // which we will always try to inline if the other non-instruction limits
59 // are not reached.
60 static constexpr size_t kMaximumNumberOfInstructionsForSmallMethod = 3;
61
62 // Limit the number of dex registers that we accumulate while inlining
63 // to avoid creating large amount of nested environments.
64 static constexpr size_t kMaximumNumberOfCumulatedDexRegisters = 32;
65
66 // Limit recursive call inlining, which do not benefit from too
67 // much inlining compared to code locality.
68 static constexpr size_t kMaximumNumberOfRecursiveCalls = 4;
69
70 // Limit recursive polymorphic call inlining to prevent code bloat, since it can quickly get out of
71 // hand in the presence of multiple Wrapper classes. We set this to 0 to disallow polymorphic
72 // recursive calls at all.
73 static constexpr size_t kMaximumNumberOfPolymorphicRecursiveCalls = 0;
74
75 // Controls the use of inline caches in AOT mode.
76 static constexpr bool kUseAOTInlineCaches = true;
77
78 // Controls the use of inlining try catches.
79 static constexpr bool kInlineTryCatches = true;
80
81 // We check for line numbers to make sure the DepthString implementation
82 // aligns the output nicely.
83 #define LOG_INTERNAL(msg) \
84 static_assert(__LINE__ > 10, "Unhandled line number"); \
85 static_assert(__LINE__ < 10000, "Unhandled line number"); \
86 VLOG(compiler) << DepthString(__LINE__) << msg
87
88 #define LOG_TRY() LOG_INTERNAL("Try inlinining call: ")
89 #define LOG_NOTE() LOG_INTERNAL("Note: ")
90 #define LOG_SUCCESS() LOG_INTERNAL("Success: ")
91 #define LOG_FAIL(stats_ptr, stat) MaybeRecordStat(stats_ptr, stat); LOG_INTERNAL("Fail: ")
92 #define LOG_FAIL_NO_STAT() LOG_INTERNAL("Fail: ")
93
DepthString(int line) const94 std::string HInliner::DepthString(int line) const {
95 std::string value;
96 // Indent according to the inlining depth.
97 size_t count = depth_;
98 // Line numbers get printed in the log, so add a space if the log's line is less
99 // than 1000, and two if less than 100. 10 cannot be reached as it's the copyright.
100 if (!kIsTargetBuild) {
101 if (line < 100) {
102 value += " ";
103 }
104 if (line < 1000) {
105 value += " ";
106 }
107 // Safeguard if this file reaches more than 10000 lines.
108 DCHECK_LT(line, 10000);
109 }
110 for (size_t i = 0; i < count; ++i) {
111 value += " ";
112 }
113 return value;
114 }
115
CountNumberOfInstructions(HGraph * graph)116 static size_t CountNumberOfInstructions(HGraph* graph) {
117 size_t number_of_instructions = 0;
118 for (HBasicBlock* block : graph->GetReversePostOrderSkipEntryBlock()) {
119 for (HInstructionIterator instr_it(block->GetInstructions());
120 !instr_it.Done();
121 instr_it.Advance()) {
122 ++number_of_instructions;
123 }
124 }
125 return number_of_instructions;
126 }
127
UpdateInliningBudget()128 void HInliner::UpdateInliningBudget() {
129 if (total_number_of_instructions_ >= kMaximumNumberOfTotalInstructions) {
130 // Always try to inline small methods.
131 inlining_budget_ = kMaximumNumberOfInstructionsForSmallMethod;
132 } else {
133 inlining_budget_ = std::max(
134 kMaximumNumberOfInstructionsForSmallMethod,
135 kMaximumNumberOfTotalInstructions - total_number_of_instructions_);
136 }
137 }
138
Run()139 bool HInliner::Run() {
140 if (codegen_->GetCompilerOptions().GetInlineMaxCodeUnits() == 0) {
141 // Inlining effectively disabled.
142 return false;
143 } else if (graph_->IsDebuggable()) {
144 // For simplicity, we currently never inline when the graph is debuggable. This avoids
145 // doing some logic in the runtime to discover if a method could have been inlined.
146 return false;
147 }
148
149 bool did_inline = false;
150
151 // Initialize the number of instructions for the method being compiled. Recursive calls
152 // to HInliner::Run have already updated the instruction count.
153 if (outermost_graph_ == graph_) {
154 total_number_of_instructions_ = CountNumberOfInstructions(graph_);
155 }
156
157 UpdateInliningBudget();
158 DCHECK_NE(total_number_of_instructions_, 0u);
159 DCHECK_NE(inlining_budget_, 0u);
160
161 // If we're compiling tests, honor inlining directives in method names:
162 // - if a method's name contains the substring "$noinline$", do not
163 // inline that method;
164 // - if a method's name contains the substring "$inline$", ensure
165 // that this method is actually inlined.
166 // We limit the latter to AOT compilation, as the JIT may or may not inline
167 // depending on the state of classes at runtime.
168 const bool honor_noinline_directives = codegen_->GetCompilerOptions().CompileArtTest();
169 const bool honor_inline_directives =
170 honor_noinline_directives &&
171 Runtime::Current()->IsAotCompiler() &&
172 !graph_->IsCompilingBaseline();
173
174 // Keep a copy of all blocks when starting the visit.
175 ArenaVector<HBasicBlock*> blocks = graph_->GetReversePostOrder();
176 DCHECK(!blocks.empty());
177 // Because we are changing the graph when inlining,
178 // we just iterate over the blocks of the outer method.
179 // This avoids doing the inlining work again on the inlined blocks.
180 for (HBasicBlock* block : blocks) {
181 for (HInstruction* instruction = block->GetFirstInstruction(); instruction != nullptr;) {
182 HInstruction* next = instruction->GetNext();
183 HInvoke* call = instruction->AsInvokeOrNull();
184 // As long as the call is not intrinsified, it is worth trying to inline.
185 if (call != nullptr && !codegen_->IsImplementedIntrinsic(call)) {
186 if (honor_noinline_directives) {
187 // Debugging case: directives in method names control or assert on inlining.
188 std::string callee_name =
189 call->GetMethodReference().PrettyMethod(/* with_signature= */ false);
190 // Tests prevent inlining by having $noinline$ in their method names.
191 if (callee_name.find("$noinline$") == std::string::npos) {
192 if (TryInline(call)) {
193 did_inline = true;
194 } else if (honor_inline_directives) {
195 bool should_have_inlined = (callee_name.find("$inline$") != std::string::npos);
196 CHECK(!should_have_inlined) << "Could not inline " << callee_name;
197 }
198 }
199 } else {
200 DCHECK(!honor_inline_directives);
201 // Normal case: try to inline.
202 if (TryInline(call)) {
203 did_inline = true;
204 }
205 }
206 }
207 instruction = next;
208 }
209 }
210
211 if (run_extra_type_propagation_) {
212 ReferenceTypePropagation rtp_fixup(graph_,
213 outer_compilation_unit_.GetDexCache(),
214 /* is_first_run= */ false);
215 rtp_fixup.Run();
216 }
217
218 // We return true if we either inlined at least one method, or we marked one of our methods as
219 // always throwing.
220 // To check if we added an always throwing method we can either:
221 // 1) Pass a boolean throughout the pipeline and get an accurate result, or
222 // 2) Just check that the `HasAlwaysThrowingInvokes()` flag is true now. This is not 100%
223 // accurate but the only other part where we set `HasAlwaysThrowingInvokes` is constant
224 // folding the DivideUnsigned intrinsics for when the divisor is known to be 0. This case is
225 // rare enough that changing the pipeline for this is not worth it. In the case of the false
226 // positive (i.e. A) we didn't inline at all, B) the graph already had an always throwing
227 // invoke, and C) we didn't set any new always throwing invokes), we will be running constant
228 // folding, instruction simplifier, and dead code elimination one more time even though it
229 // shouldn't change things. There's no false negative case.
230 return did_inline || graph_->HasAlwaysThrowingInvokes();
231 }
232
IsMethodOrDeclaringClassFinal(ArtMethod * method)233 static bool IsMethodOrDeclaringClassFinal(ArtMethod* method)
234 REQUIRES_SHARED(Locks::mutator_lock_) {
235 return method->IsFinal() || method->GetDeclaringClass()->IsFinal();
236 }
237
238 /**
239 * Given the `resolved_method` looked up in the dex cache, try to find
240 * the actual runtime target of an interface or virtual call.
241 * Return nullptr if the runtime target cannot be proven.
242 */
FindVirtualOrInterfaceTarget(HInvoke * invoke,ReferenceTypeInfo info)243 static ArtMethod* FindVirtualOrInterfaceTarget(HInvoke* invoke, ReferenceTypeInfo info)
244 REQUIRES_SHARED(Locks::mutator_lock_) {
245 ArtMethod* resolved_method = invoke->GetResolvedMethod();
246 if (IsMethodOrDeclaringClassFinal(resolved_method)) {
247 // No need to lookup further, the resolved method will be the target.
248 return resolved_method;
249 }
250
251 if (info.GetTypeHandle()->IsInterface()) {
252 // Statically knowing that the receiver has an interface type cannot
253 // help us find what is the target method.
254 return nullptr;
255 } else if (!resolved_method->GetDeclaringClass()->IsAssignableFrom(info.GetTypeHandle().Get())) {
256 // The method that we're trying to call is not in the receiver's class or super classes.
257 return nullptr;
258 } else if (info.GetTypeHandle()->IsErroneous()) {
259 // If the type is erroneous, do not go further, as we are going to query the vtable or
260 // imt table, that we can only safely do on non-erroneous classes.
261 return nullptr;
262 }
263
264 ClassLinker* cl = Runtime::Current()->GetClassLinker();
265 PointerSize pointer_size = cl->GetImagePointerSize();
266 if (invoke->IsInvokeInterface()) {
267 resolved_method = info.GetTypeHandle()->FindVirtualMethodForInterface(
268 resolved_method, pointer_size);
269 } else {
270 DCHECK(invoke->IsInvokeVirtual());
271 resolved_method = info.GetTypeHandle()->FindVirtualMethodForVirtual(
272 resolved_method, pointer_size);
273 }
274
275 if (resolved_method == nullptr) {
276 // The information we had on the receiver was not enough to find
277 // the target method. Since we check above the exact type of the receiver,
278 // the only reason this can happen is an IncompatibleClassChangeError.
279 return nullptr;
280 } else if (!resolved_method->IsInvokable()) {
281 // The information we had on the receiver was not enough to find
282 // the target method. Since we check above the exact type of the receiver,
283 // the only reason this can happen is an IncompatibleClassChangeError.
284 return nullptr;
285 } else if (IsMethodOrDeclaringClassFinal(resolved_method)) {
286 // A final method has to be the target method.
287 return resolved_method;
288 } else if (info.IsExact()) {
289 // If we found a method and the receiver's concrete type is statically
290 // known, we know for sure the target.
291 return resolved_method;
292 } else {
293 // Even if we did find a method, the receiver type was not enough to
294 // statically find the runtime target.
295 return nullptr;
296 }
297 }
298
FindMethodIndexIn(ArtMethod * method,const DexFile & dex_file,uint32_t name_and_signature_index)299 static uint32_t FindMethodIndexIn(ArtMethod* method,
300 const DexFile& dex_file,
301 uint32_t name_and_signature_index)
302 REQUIRES_SHARED(Locks::mutator_lock_) {
303 if (IsSameDexFile(*method->GetDexFile(), dex_file)) {
304 return method->GetDexMethodIndex();
305 } else {
306 return method->FindDexMethodIndexInOtherDexFile(dex_file, name_and_signature_index);
307 }
308 }
309
FindClassIndexIn(ObjPtr<mirror::Class> cls,const DexCompilationUnit & compilation_unit)310 static dex::TypeIndex FindClassIndexIn(ObjPtr<mirror::Class> cls,
311 const DexCompilationUnit& compilation_unit)
312 REQUIRES_SHARED(Locks::mutator_lock_) {
313 const DexFile& dex_file = *compilation_unit.GetDexFile();
314 dex::TypeIndex index;
315 if (cls->GetDexCache() == nullptr) {
316 DCHECK(cls->IsArrayClass()) << cls->PrettyClass();
317 index = cls->FindTypeIndexInOtherDexFile(dex_file);
318 } else if (!cls->GetDexTypeIndex().IsValid()) {
319 DCHECK(cls->IsProxyClass()) << cls->PrettyClass();
320 // TODO: deal with proxy classes.
321 } else if (IsSameDexFile(cls->GetDexFile(), dex_file)) {
322 DCHECK_EQ(cls->GetDexCache(), compilation_unit.GetDexCache().Get());
323 index = cls->GetDexTypeIndex();
324 } else {
325 index = cls->FindTypeIndexInOtherDexFile(dex_file);
326 // We cannot guarantee the entry will resolve to the same class,
327 // as there may be different class loaders. So only return the index if it's
328 // the right class already resolved with the class loader.
329 if (index.IsValid()) {
330 ObjPtr<mirror::Class> resolved = compilation_unit.GetClassLinker()->LookupResolvedType(
331 index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get());
332 if (resolved != cls) {
333 index = dex::TypeIndex::Invalid();
334 }
335 }
336 }
337
338 return index;
339 }
340
GetInlineCacheType(const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)341 HInliner::InlineCacheType HInliner::GetInlineCacheType(
342 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
343 DCHECK_EQ(classes.Capacity(), InlineCache::kIndividualCacheSize);
344 uint8_t number_of_types = classes.Size();
345 if (number_of_types == 0) {
346 return kInlineCacheUninitialized;
347 } else if (number_of_types == 1) {
348 return kInlineCacheMonomorphic;
349 } else if (number_of_types == InlineCache::kIndividualCacheSize) {
350 return kInlineCacheMegamorphic;
351 } else {
352 return kInlineCachePolymorphic;
353 }
354 }
355
GetMonomorphicType(const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)356 static inline ObjPtr<mirror::Class> GetMonomorphicType(
357 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes)
358 REQUIRES_SHARED(Locks::mutator_lock_) {
359 DCHECK(classes.GetReference(0) != nullptr);
360 return classes.GetReference(0)->AsClass();
361 }
362
FindMethodFromCHA(ArtMethod * resolved_method)363 ArtMethod* HInliner::FindMethodFromCHA(ArtMethod* resolved_method) {
364 if (!resolved_method->HasSingleImplementation()) {
365 return nullptr;
366 }
367 if (Runtime::Current()->IsAotCompiler()) {
368 // No CHA-based devirtulization for AOT compiler (yet).
369 return nullptr;
370 }
371 if (Runtime::Current()->IsZygote()) {
372 // No CHA-based devirtulization for Zygote, as it compiles with
373 // offline information.
374 return nullptr;
375 }
376 if (outermost_graph_->IsCompilingOsr()) {
377 // We do not support HDeoptimize in OSR methods.
378 return nullptr;
379 }
380 PointerSize pointer_size = caller_compilation_unit_.GetClassLinker()->GetImagePointerSize();
381 ArtMethod* single_impl = resolved_method->GetSingleImplementation(pointer_size);
382 if (single_impl == nullptr) {
383 return nullptr;
384 }
385 if (single_impl->IsProxyMethod()) {
386 // Proxy method is a generic invoker that's not worth
387 // devirtualizing/inlining. It also causes issues when the proxy
388 // method is in another dex file if we try to rewrite invoke-interface to
389 // invoke-virtual because a proxy method doesn't have a real dex file.
390 return nullptr;
391 }
392 if (!single_impl->GetDeclaringClass()->IsResolved()) {
393 // There's a race with the class loading, which updates the CHA info
394 // before setting the class to resolved. So we just bail for this
395 // rare occurence.
396 return nullptr;
397 }
398 return single_impl;
399 }
400
IsMethodVerified(ArtMethod * method)401 static bool IsMethodVerified(ArtMethod* method)
402 REQUIRES_SHARED(Locks::mutator_lock_) {
403 if (method->GetDeclaringClass()->IsVerified()) {
404 return true;
405 }
406 // For AOT, we check if the class has a verification status that allows us to
407 // inline / analyze.
408 // At runtime, we know this is cold code if the class is not verified, so don't
409 // bother analyzing.
410 if (Runtime::Current()->IsAotCompiler()) {
411 if (method->GetDeclaringClass()->IsVerifiedNeedsAccessChecks()) {
412 DCHECK(!Runtime::Current()->GetCompilerCallbacks()->IsUncompilableMethod(
413 MethodReference(method->GetDexFile(), method->GetDexMethodIndex())));
414 return true;
415 }
416 if (method->GetDeclaringClass()->ShouldVerifyAtRuntime()) {
417 return !Runtime::Current()->GetCompilerCallbacks()->IsUncompilableMethod(
418 MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
419 }
420 }
421 return false;
422 }
423
AlwaysThrows(ArtMethod * method)424 static bool AlwaysThrows(ArtMethod* method)
425 REQUIRES_SHARED(Locks::mutator_lock_) {
426 DCHECK(method != nullptr);
427 // Skip non-compilable and unverified methods.
428 if (!method->IsCompilable() || !IsMethodVerified(method)) {
429 return false;
430 }
431
432 // Skip native methods, methods with try blocks, and methods that are too large.
433 // TODO(solanes): We could correctly mark methods with try/catch blocks as always throwing as long
434 // as we can get rid of the infinite loop cases. These cases (e.g. `void foo() {while (true) {}}`)
435 // are the only ones that can have no return instruction and still not be an "always throwing
436 // method". Unfortunately, we need to construct the graph to know there's an infinite loop and
437 // therefore not worth the trouble.
438 CodeItemDataAccessor accessor(method->DexInstructionData());
439 if (!accessor.HasCodeItem() ||
440 accessor.TriesSize() != 0 ||
441 accessor.InsnsSizeInCodeUnits() > kMaximumNumberOfTotalInstructions) {
442 return false;
443 }
444 // Scan for exits.
445 bool throw_seen = false;
446 for (const DexInstructionPcPair& pair : accessor) {
447 switch (pair.Inst().Opcode()) {
448 case Instruction::RETURN:
449 case Instruction::RETURN_VOID:
450 case Instruction::RETURN_WIDE:
451 case Instruction::RETURN_OBJECT:
452 return false; // found regular control flow back
453 case Instruction::THROW:
454 throw_seen = true;
455 break;
456 default:
457 break;
458 }
459 }
460 return throw_seen;
461 }
462
TryInline(HInvoke * invoke_instruction)463 bool HInliner::TryInline(HInvoke* invoke_instruction) {
464 MaybeRecordStat(stats_, MethodCompilationStat::kTryInline);
465
466 // Don't bother to move further if we know the method is unresolved or the invocation is
467 // polymorphic (invoke-{polymorphic,custom}).
468 if (invoke_instruction->IsInvokeUnresolved()) {
469 MaybeRecordStat(stats_, MethodCompilationStat::kNotInlinedUnresolved);
470 return false;
471 } else if (invoke_instruction->IsInvokePolymorphic()) {
472 MaybeRecordStat(stats_, MethodCompilationStat::kNotInlinedPolymorphic);
473 return false;
474 } else if (invoke_instruction->IsInvokeCustom()) {
475 MaybeRecordStat(stats_, MethodCompilationStat::kNotInlinedCustom);
476 return false;
477 }
478
479 ScopedObjectAccess soa(Thread::Current());
480 LOG_TRY() << invoke_instruction->GetMethodReference().PrettyMethod();
481
482 ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
483 if (resolved_method == nullptr) {
484 DCHECK(invoke_instruction->IsInvokeStaticOrDirect());
485 DCHECK(invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit());
486 LOG_FAIL_NO_STAT() << "Not inlining a String.<init> method";
487 return false;
488 }
489
490 ArtMethod* actual_method = nullptr;
491 ReferenceTypeInfo receiver_info = ReferenceTypeInfo::CreateInvalid();
492 if (invoke_instruction->GetInvokeType() == kStatic) {
493 actual_method = invoke_instruction->GetResolvedMethod();
494 } else {
495 HInstruction* receiver = invoke_instruction->InputAt(0);
496 while (receiver->IsNullCheck()) {
497 // Due to multiple levels of inlining within the same pass, it might be that
498 // null check does not have the reference type of the actual receiver.
499 receiver = receiver->InputAt(0);
500 }
501 receiver_info = receiver->GetReferenceTypeInfo();
502 if (!receiver_info.IsValid()) {
503 // We have to run the extra type propagation now as we are requiring the RTI.
504 DCHECK(run_extra_type_propagation_);
505 run_extra_type_propagation_ = false;
506 ReferenceTypePropagation rtp_fixup(graph_,
507 outer_compilation_unit_.GetDexCache(),
508 /* is_first_run= */ false);
509 rtp_fixup.Run();
510 receiver_info = receiver->GetReferenceTypeInfo();
511 }
512
513 DCHECK(receiver_info.IsValid()) << "Invalid RTI for " << receiver->DebugName();
514 if (invoke_instruction->IsInvokeStaticOrDirect()) {
515 actual_method = invoke_instruction->GetResolvedMethod();
516 } else {
517 actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, receiver_info);
518 }
519 }
520
521 if (actual_method != nullptr) {
522 // Single target.
523 bool result = TryInlineAndReplace(invoke_instruction,
524 actual_method,
525 receiver_info,
526 /* do_rtp= */ true,
527 /* is_speculative= */ false);
528 if (result) {
529 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvokeVirtualOrInterface);
530 if (outermost_graph_ == graph_) {
531 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedLastInvokeVirtualOrInterface);
532 }
533 } else {
534 HInvoke* invoke_to_analyze = nullptr;
535 if (TryDevirtualize(invoke_instruction, actual_method, &invoke_to_analyze)) {
536 // Consider devirtualization as inlining.
537 result = true;
538 MaybeRecordStat(stats_, MethodCompilationStat::kDevirtualized);
539 } else {
540 invoke_to_analyze = invoke_instruction;
541 }
542 // Set always throws property for non-inlined method call with single target.
543 if (invoke_instruction->AlwaysThrows() || AlwaysThrows(actual_method)) {
544 invoke_to_analyze->SetAlwaysThrows(/* always_throws= */ true);
545 graph_->SetHasAlwaysThrowingInvokes(/* value= */ true);
546 }
547 }
548 return result;
549 }
550
551 if (graph_->IsCompilingBaseline()) {
552 LOG_FAIL_NO_STAT() << "Call to " << invoke_instruction->GetMethodReference().PrettyMethod()
553 << " not inlined because we are compiling baseline and we could not"
554 << " statically resolve the target";
555 // For baseline compilation, we will collect inline caches, so we should not
556 // try to inline using them.
557 outermost_graph_->SetUsefulOptimizing();
558 return false;
559 }
560
561 DCHECK(!invoke_instruction->IsInvokeStaticOrDirect());
562
563 // No try catch inlining allowed here, or recursively. For try catch inlining we are banking on
564 // the fact that we have a unique dex pc list. We cannot guarantee that for some TryInline methods
565 // e.g. `TryInlinePolymorphicCall`.
566 // TODO(solanes): Setting `try_catch_inlining_allowed_` to false here covers all cases from
567 // `TryInlineFromCHA` and from `TryInlineFromInlineCache` as well (e.g.
568 // `TryInlinePolymorphicCall`). Reassess to see if we can inline inline catch blocks in
569 // `TryInlineFromCHA`, `TryInlineMonomorphicCall` and `TryInlinePolymorphicCallToSameTarget`.
570
571 // We store the value to restore it since we will use the same HInliner instance for other inlinee
572 // candidates.
573 const bool previous_value = try_catch_inlining_allowed_;
574 try_catch_inlining_allowed_ = false;
575
576 if (TryInlineFromCHA(invoke_instruction)) {
577 try_catch_inlining_allowed_ = previous_value;
578 return true;
579 }
580
581 const bool result = TryInlineFromInlineCache(invoke_instruction);
582 try_catch_inlining_allowed_ = previous_value;
583 return result;
584 }
585
TryInlineFromCHA(HInvoke * invoke_instruction)586 bool HInliner::TryInlineFromCHA(HInvoke* invoke_instruction) {
587 ArtMethod* method = FindMethodFromCHA(invoke_instruction->GetResolvedMethod());
588 if (method == nullptr) {
589 return false;
590 }
591 LOG_NOTE() << "Try CHA-based inlining of " << method->PrettyMethod();
592
593 uint32_t dex_pc = invoke_instruction->GetDexPc();
594 HInstruction* cursor = invoke_instruction->GetPrevious();
595 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
596 Handle<mirror::Class> cls = graph_->GetHandleCache()->NewHandle(method->GetDeclaringClass());
597 if (!TryInlineAndReplace(invoke_instruction,
598 method,
599 ReferenceTypeInfo::Create(cls),
600 /* do_rtp= */ true,
601 /* is_speculative= */ true)) {
602 return false;
603 }
604 AddCHAGuard(invoke_instruction, dex_pc, cursor, bb_cursor);
605 // Add dependency due to devirtualization: we are assuming the resolved method
606 // has a single implementation.
607 outermost_graph_->AddCHASingleImplementationDependency(invoke_instruction->GetResolvedMethod());
608 MaybeRecordStat(stats_, MethodCompilationStat::kCHAInline);
609 return true;
610 }
611
UseOnlyPolymorphicInliningWithNoDeopt()612 bool HInliner::UseOnlyPolymorphicInliningWithNoDeopt() {
613 // If we are compiling AOT or OSR, pretend the call using inline caches is polymorphic and
614 // do not generate a deopt.
615 //
616 // For AOT:
617 // Generating a deopt does not ensure that we will actually capture the new types;
618 // and the danger is that we could be stuck in a loop with "forever" deoptimizations.
619 // Take for example the following scenario:
620 // - we capture the inline cache in one run
621 // - the next run, we deoptimize because we miss a type check, but the method
622 // never becomes hot again
623 // In this case, the inline cache will not be updated in the profile and the AOT code
624 // will keep deoptimizing.
625 // Another scenario is if we use profile compilation for a process which is not allowed
626 // to JIT (e.g. system server). If we deoptimize we will run interpreted code for the
627 // rest of the lifetime.
628 // TODO(calin):
629 // This is a compromise because we will most likely never update the inline cache
630 // in the profile (unless there's another reason to deopt). So we might be stuck with
631 // a sub-optimal inline cache.
632 // We could be smarter when capturing inline caches to mitigate this.
633 // (e.g. by having different thresholds for new and old methods).
634 //
635 // For OSR:
636 // We may come from the interpreter and it may have seen different receiver types.
637 return Runtime::Current()->IsAotCompiler() || outermost_graph_->IsCompilingOsr();
638 }
TryInlineFromInlineCache(HInvoke * invoke_instruction)639 bool HInliner::TryInlineFromInlineCache(HInvoke* invoke_instruction)
640 REQUIRES_SHARED(Locks::mutator_lock_) {
641 if (Runtime::Current()->IsAotCompiler() && !kUseAOTInlineCaches) {
642 return false;
643 }
644
645 StackHandleScope<InlineCache::kIndividualCacheSize> classes(Thread::Current());
646 // The Zygote JIT compiles based on a profile, so we shouldn't use runtime inline caches
647 // for it.
648 InlineCacheType inline_cache_type =
649 (Runtime::Current()->IsAotCompiler() || Runtime::Current()->IsZygote())
650 ? GetInlineCacheAOT(invoke_instruction, &classes)
651 : GetInlineCacheJIT(invoke_instruction, &classes);
652
653 switch (inline_cache_type) {
654 case kInlineCacheNoData: {
655 LOG_FAIL_NO_STAT()
656 << "No inline cache information for call to "
657 << invoke_instruction->GetMethodReference().PrettyMethod();
658 return false;
659 }
660
661 case kInlineCacheUninitialized: {
662 LOG_FAIL_NO_STAT()
663 << "Interface or virtual call to "
664 << invoke_instruction->GetMethodReference().PrettyMethod()
665 << " is not hit and not inlined";
666 return false;
667 }
668
669 case kInlineCacheMonomorphic: {
670 MaybeRecordStat(stats_, MethodCompilationStat::kMonomorphicCall);
671 if (UseOnlyPolymorphicInliningWithNoDeopt()) {
672 return TryInlinePolymorphicCall(invoke_instruction, classes);
673 } else {
674 return TryInlineMonomorphicCall(invoke_instruction, classes);
675 }
676 }
677
678 case kInlineCachePolymorphic: {
679 MaybeRecordStat(stats_, MethodCompilationStat::kPolymorphicCall);
680 return TryInlinePolymorphicCall(invoke_instruction, classes);
681 }
682
683 case kInlineCacheMegamorphic: {
684 LOG_FAIL_NO_STAT()
685 << "Interface or virtual call to "
686 << invoke_instruction->GetMethodReference().PrettyMethod()
687 << " is megamorphic and not inlined";
688 MaybeRecordStat(stats_, MethodCompilationStat::kMegamorphicCall);
689 return false;
690 }
691
692 case kInlineCacheMissingTypes: {
693 LOG_FAIL_NO_STAT()
694 << "Interface or virtual call to "
695 << invoke_instruction->GetMethodReference().PrettyMethod()
696 << " is missing types and not inlined";
697 return false;
698 }
699 }
700 }
701
GetInlineCacheJIT(HInvoke * invoke_instruction,StackHandleScope<InlineCache::kIndividualCacheSize> * classes)702 HInliner::InlineCacheType HInliner::GetInlineCacheJIT(
703 HInvoke* invoke_instruction,
704 /*out*/StackHandleScope<InlineCache::kIndividualCacheSize>* classes) {
705 DCHECK(codegen_->GetCompilerOptions().IsJitCompiler());
706
707 ArtMethod* caller = graph_->GetArtMethod();
708 // Under JIT, we should always know the caller.
709 DCHECK(caller != nullptr);
710
711 InlineCache* cache = nullptr;
712 // Start with the outer graph profiling info.
713 ProfilingInfo* profiling_info = outermost_graph_->GetProfilingInfo();
714 if (profiling_info != nullptr) {
715 if (depth_ == 0) {
716 cache = profiling_info->GetInlineCache(invoke_instruction->GetDexPc());
717 } else {
718 uint32_t dex_pc = ProfilingInfoBuilder::EncodeInlinedDexPc(
719 this, codegen_->GetCompilerOptions(), invoke_instruction);
720 if (dex_pc != kNoDexPc) {
721 cache = profiling_info->GetInlineCache(dex_pc);
722 }
723 }
724 }
725
726 if (cache == nullptr) {
727 // Check the current graph profiling info.
728 profiling_info = graph_->GetProfilingInfo();
729 if (profiling_info == nullptr) {
730 return kInlineCacheNoData;
731 }
732
733 cache = profiling_info->GetInlineCache(invoke_instruction->GetDexPc());
734 }
735
736 if (cache == nullptr) {
737 // Either we never hit this invoke and we never compiled the callee,
738 // or the method wasn't resolved when we performed baseline compilation.
739 // Bail for now.
740 return kInlineCacheNoData;
741 }
742 Runtime::Current()->GetJit()->GetCodeCache()->CopyInlineCacheInto(*cache, classes);
743 return GetInlineCacheType(*classes);
744 }
745
GetInlineCacheAOT(HInvoke * invoke_instruction,StackHandleScope<InlineCache::kIndividualCacheSize> * classes)746 HInliner::InlineCacheType HInliner::GetInlineCacheAOT(
747 HInvoke* invoke_instruction,
748 /*out*/StackHandleScope<InlineCache::kIndividualCacheSize>* classes) {
749 DCHECK_EQ(classes->Capacity(), InlineCache::kIndividualCacheSize);
750 DCHECK_EQ(classes->Size(), 0u);
751
752 const ProfileCompilationInfo* pci = codegen_->GetCompilerOptions().GetProfileCompilationInfo();
753 if (pci == nullptr) {
754 return kInlineCacheNoData;
755 }
756
757 ProfileCompilationInfo::MethodHotness hotness = pci->GetMethodHotness(MethodReference(
758 caller_compilation_unit_.GetDexFile(), caller_compilation_unit_.GetDexMethodIndex()));
759 if (!hotness.IsHot()) {
760 return kInlineCacheNoData; // no profile information for this invocation.
761 }
762
763 const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
764 DCHECK(inline_caches != nullptr);
765
766 // Inlined inline caches are not supported in AOT, so we use the dex pc directly, and don't
767 // call `InlineCache::EncodeDexPc`.
768 // To support it, we would need to ensure `inline_max_code_units` remain the
769 // same between dex2oat and runtime, for example by adding it to the boot
770 // image oat header.
771 const auto it = inline_caches->find(invoke_instruction->GetDexPc());
772 if (it == inline_caches->end()) {
773 return kInlineCacheUninitialized;
774 }
775
776 const ProfileCompilationInfo::DexPcData& dex_pc_data = it->second;
777 if (dex_pc_data.is_missing_types) {
778 return kInlineCacheMissingTypes;
779 }
780 if (dex_pc_data.is_megamorphic) {
781 return kInlineCacheMegamorphic;
782 }
783 DCHECK_LE(dex_pc_data.classes.size(), InlineCache::kIndividualCacheSize);
784
785 // Walk over the class descriptors and look up the actual classes.
786 // If we cannot find a type we return kInlineCacheMissingTypes.
787 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
788 Thread* self = Thread::Current();
789 for (const dex::TypeIndex& type_index : dex_pc_data.classes) {
790 const DexFile* dex_file = caller_compilation_unit_.GetDexFile();
791 size_t descriptor_length;
792 const char* descriptor = pci->GetTypeDescriptor(dex_file, type_index, &descriptor_length);
793 ObjPtr<mirror::Class> clazz = class_linker->FindClass(
794 self, descriptor, descriptor_length, caller_compilation_unit_.GetClassLoader());
795 if (clazz == nullptr) {
796 self->ClearException(); // Clean up the exception left by type resolution.
797 VLOG(compiler) << "Could not find class from inline cache in AOT mode "
798 << invoke_instruction->GetMethodReference().PrettyMethod()
799 << " : "
800 << descriptor;
801 return kInlineCacheMissingTypes;
802 }
803 DCHECK_LT(classes->Size(), classes->Capacity());
804 classes->NewHandle(clazz);
805 }
806
807 return GetInlineCacheType(*classes);
808 }
809
BuildGetReceiverClass(HInstruction * receiver,uint32_t dex_pc) const810 HInstanceFieldGet* HInliner::BuildGetReceiverClass(HInstruction* receiver,
811 uint32_t dex_pc) const {
812 ArtField* field = WellKnownClasses::java_lang_Object_shadowKlass;
813 HInstanceFieldGet* result = new (graph_->GetAllocator()) HInstanceFieldGet(
814 receiver,
815 field,
816 DataType::Type::kReference,
817 field->GetOffset(),
818 field->IsVolatile(),
819 field->GetDexFieldIndex(),
820 field->GetDeclaringClass()->GetDexClassDefIndex(),
821 *field->GetDexFile(),
822 dex_pc);
823 // The class of a field is effectively final, and does not have any memory dependencies.
824 result->SetSideEffects(SideEffects::None());
825 return result;
826 }
827
ResolveMethodFromInlineCache(Handle<mirror::Class> klass,HInvoke * invoke_instruction,PointerSize pointer_size)828 static ArtMethod* ResolveMethodFromInlineCache(Handle<mirror::Class> klass,
829 HInvoke* invoke_instruction,
830 PointerSize pointer_size)
831 REQUIRES_SHARED(Locks::mutator_lock_) {
832 ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
833 if (Runtime::Current()->IsAotCompiler()) {
834 // We can get unrelated types when working with profiles (corruption,
835 // systme updates, or anyone can write to it). So first check if the class
836 // actually implements the declaring class of the method that is being
837 // called in bytecode.
838 // Note: the lookup methods used below require to have assignable types.
839 if (!resolved_method->GetDeclaringClass()->IsAssignableFrom(klass.Get())) {
840 return nullptr;
841 }
842
843 // Also check whether the type in the inline cache is an interface or an
844 // abstract class. We only expect concrete classes in inline caches, so this
845 // means the class was changed.
846 if (klass->IsAbstract() || klass->IsInterface()) {
847 return nullptr;
848 }
849 }
850
851 if (invoke_instruction->IsInvokeInterface()) {
852 resolved_method = klass->FindVirtualMethodForInterface(resolved_method, pointer_size);
853 } else {
854 DCHECK(invoke_instruction->IsInvokeVirtual());
855 resolved_method = klass->FindVirtualMethodForVirtual(resolved_method, pointer_size);
856 }
857 // Even if the class exists we can still not have the function the
858 // inline-cache targets if the profile is from far enough in the past/future.
859 // We need to allow this since we don't update boot-profiles very often. This
860 // can occur in boot-profiles with inline-caches.
861 DCHECK(Runtime::Current()->IsAotCompiler() || resolved_method != nullptr);
862 return resolved_method;
863 }
864
TryInlineMonomorphicCall(HInvoke * invoke_instruction,const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)865 bool HInliner::TryInlineMonomorphicCall(
866 HInvoke* invoke_instruction,
867 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
868 DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface())
869 << invoke_instruction->DebugName();
870
871 dex::TypeIndex class_index = FindClassIndexIn(
872 GetMonomorphicType(classes), caller_compilation_unit_);
873 if (!class_index.IsValid()) {
874 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedDexCacheInaccessibleToCaller)
875 << "Call to " << ArtMethod::PrettyMethod(invoke_instruction->GetResolvedMethod())
876 << " from inline cache is not inlined because its class is not"
877 << " accessible to the caller";
878 return false;
879 }
880
881 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
882 PointerSize pointer_size = class_linker->GetImagePointerSize();
883 Handle<mirror::Class> monomorphic_type =
884 graph_->GetHandleCache()->NewHandle(GetMonomorphicType(classes));
885 ArtMethod* resolved_method = ResolveMethodFromInlineCache(
886 monomorphic_type, invoke_instruction, pointer_size);
887 if (resolved_method == nullptr) {
888 // Bogus AOT profile, bail.
889 DCHECK(Runtime::Current()->IsAotCompiler());
890 return false;
891 }
892
893 LOG_NOTE() << "Try inline monomorphic call to " << resolved_method->PrettyMethod();
894 HInstruction* receiver = invoke_instruction->InputAt(0);
895 HInstruction* cursor = invoke_instruction->GetPrevious();
896 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
897 if (!TryInlineAndReplace(invoke_instruction,
898 resolved_method,
899 ReferenceTypeInfo::Create(monomorphic_type, /* is_exact= */ true),
900 /* do_rtp= */ false,
901 /* is_speculative= */ true)) {
902 return false;
903 }
904
905 // We successfully inlined, now add a guard.
906 AddTypeGuard(receiver,
907 cursor,
908 bb_cursor,
909 class_index,
910 monomorphic_type,
911 invoke_instruction,
912 /* with_deoptimization= */ true);
913
914 // Lazily run type propagation to get the guard typed, and eventually propagate the
915 // type of the receiver.
916 run_extra_type_propagation_ = true;
917
918 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedMonomorphicCall);
919 return true;
920 }
921
AddCHAGuard(HInstruction * invoke_instruction,uint32_t dex_pc,HInstruction * cursor,HBasicBlock * bb_cursor)922 void HInliner::AddCHAGuard(HInstruction* invoke_instruction,
923 uint32_t dex_pc,
924 HInstruction* cursor,
925 HBasicBlock* bb_cursor) {
926 HShouldDeoptimizeFlag* deopt_flag = new (graph_->GetAllocator())
927 HShouldDeoptimizeFlag(graph_->GetAllocator(), dex_pc);
928 // ShouldDeoptimizeFlag is used to perform a deoptimization because of a CHA
929 // invalidation or for debugging reasons. It is OK to just check for non-zero
930 // value here instead of the specific CHA value. When a debugging deopt is
931 // requested we deoptimize before we execute any code and hence we shouldn't
932 // see that case here.
933 HInstruction* compare = new (graph_->GetAllocator()) HNotEqual(
934 deopt_flag, graph_->GetIntConstant(0));
935 HInstruction* deopt = new (graph_->GetAllocator()) HDeoptimize(
936 graph_->GetAllocator(), compare, DeoptimizationKind::kCHA, dex_pc);
937
938 if (cursor != nullptr) {
939 bb_cursor->InsertInstructionAfter(deopt_flag, cursor);
940 } else {
941 bb_cursor->InsertInstructionBefore(deopt_flag, bb_cursor->GetFirstInstruction());
942 }
943 bb_cursor->InsertInstructionAfter(compare, deopt_flag);
944 bb_cursor->InsertInstructionAfter(deopt, compare);
945
946 // Add receiver as input to aid CHA guard optimization later.
947 deopt_flag->AddInput(invoke_instruction->InputAt(0));
948 DCHECK_EQ(deopt_flag->InputCount(), 1u);
949 deopt->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
950 outermost_graph_->IncrementNumberOfCHAGuards();
951 }
952
AddTypeGuard(HInstruction * receiver,HInstruction * cursor,HBasicBlock * bb_cursor,dex::TypeIndex class_index,Handle<mirror::Class> klass,HInstruction * invoke_instruction,bool with_deoptimization)953 HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
954 HInstruction* cursor,
955 HBasicBlock* bb_cursor,
956 dex::TypeIndex class_index,
957 Handle<mirror::Class> klass,
958 HInstruction* invoke_instruction,
959 bool with_deoptimization) {
960 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
961 HInstanceFieldGet* receiver_class = BuildGetReceiverClass(
962 receiver, invoke_instruction->GetDexPc());
963 if (cursor != nullptr) {
964 bb_cursor->InsertInstructionAfter(receiver_class, cursor);
965 } else {
966 bb_cursor->InsertInstructionBefore(receiver_class, bb_cursor->GetFirstInstruction());
967 }
968
969 const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
970 bool is_referrer;
971 ArtMethod* outermost_art_method = outermost_graph_->GetArtMethod();
972 if (outermost_art_method == nullptr) {
973 DCHECK(Runtime::Current()->IsAotCompiler());
974 // We are in AOT mode and we don't have an ART method to determine
975 // if the inlined method belongs to the referrer. Assume it doesn't.
976 is_referrer = false;
977 } else {
978 is_referrer = klass.Get() == outermost_art_method->GetDeclaringClass();
979 }
980
981 // Note that we will just compare the classes, so we don't need Java semantics access checks.
982 // Note that the type index and the dex file are relative to the method this type guard is
983 // inlined into.
984 HLoadClass* load_class = new (graph_->GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
985 class_index,
986 caller_dex_file,
987 klass,
988 is_referrer,
989 invoke_instruction->GetDexPc(),
990 /* needs_access_check= */ false);
991 HLoadClass::LoadKind kind = HSharpening::ComputeLoadClassKind(
992 load_class, codegen_, caller_compilation_unit_);
993 DCHECK(kind != HLoadClass::LoadKind::kInvalid)
994 << "We should always be able to reference a class for inline caches";
995 // Load kind must be set before inserting the instruction into the graph.
996 load_class->SetLoadKind(kind);
997 bb_cursor->InsertInstructionAfter(load_class, receiver_class);
998 // In AOT mode, we will most likely load the class from BSS, which will involve a call
999 // to the runtime. In this case, the load instruction will need an environment so copy
1000 // it from the invoke instruction.
1001 if (load_class->NeedsEnvironment()) {
1002 DCHECK(Runtime::Current()->IsAotCompiler());
1003 load_class->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1004 }
1005
1006 HNotEqual* compare = new (graph_->GetAllocator()) HNotEqual(load_class, receiver_class);
1007 bb_cursor->InsertInstructionAfter(compare, load_class);
1008 if (with_deoptimization) {
1009 HDeoptimize* deoptimize = new (graph_->GetAllocator()) HDeoptimize(
1010 graph_->GetAllocator(),
1011 compare,
1012 receiver,
1013 Runtime::Current()->IsAotCompiler()
1014 ? DeoptimizationKind::kAotInlineCache
1015 : DeoptimizationKind::kJitInlineCache,
1016 invoke_instruction->GetDexPc());
1017 bb_cursor->InsertInstructionAfter(deoptimize, compare);
1018 deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1019 DCHECK_EQ(invoke_instruction->InputAt(0), receiver);
1020 receiver->ReplaceUsesDominatedBy(deoptimize, deoptimize);
1021 deoptimize->SetReferenceTypeInfo(receiver->GetReferenceTypeInfo());
1022 }
1023 return compare;
1024 }
1025
MaybeReplaceAndRemove(HInstruction * new_instruction,HInstruction * old_instruction)1026 static void MaybeReplaceAndRemove(HInstruction* new_instruction, HInstruction* old_instruction) {
1027 DCHECK(new_instruction != old_instruction);
1028 if (new_instruction != nullptr) {
1029 old_instruction->ReplaceWith(new_instruction);
1030 }
1031 old_instruction->GetBlock()->RemoveInstruction(old_instruction);
1032 }
1033
TryInlinePolymorphicCall(HInvoke * invoke_instruction,const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)1034 bool HInliner::TryInlinePolymorphicCall(
1035 HInvoke* invoke_instruction,
1036 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
1037 DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface())
1038 << invoke_instruction->DebugName();
1039
1040 if (TryInlinePolymorphicCallToSameTarget(invoke_instruction, classes)) {
1041 return true;
1042 }
1043
1044 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
1045 PointerSize pointer_size = class_linker->GetImagePointerSize();
1046
1047 bool all_targets_inlined = true;
1048 bool one_target_inlined = false;
1049 DCHECK_EQ(classes.Capacity(), InlineCache::kIndividualCacheSize);
1050 uint8_t number_of_types = classes.Size();
1051 for (size_t i = 0; i != number_of_types; ++i) {
1052 DCHECK(classes.GetReference(i) != nullptr);
1053 Handle<mirror::Class> handle =
1054 graph_->GetHandleCache()->NewHandle(classes.GetReference(i)->AsClass());
1055 ArtMethod* method = ResolveMethodFromInlineCache(handle, invoke_instruction, pointer_size);
1056 if (method == nullptr) {
1057 DCHECK(Runtime::Current()->IsAotCompiler());
1058 // AOT profile is bogus. This loop expects to iterate over all entries,
1059 // so just just continue.
1060 all_targets_inlined = false;
1061 continue;
1062 }
1063
1064 HInstruction* receiver = invoke_instruction->InputAt(0);
1065 HInstruction* cursor = invoke_instruction->GetPrevious();
1066 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
1067
1068 dex::TypeIndex class_index = FindClassIndexIn(handle.Get(), caller_compilation_unit_);
1069 HInstruction* return_replacement = nullptr;
1070
1071 // In monomorphic cases when UseOnlyPolymorphicInliningWithNoDeopt() is true, we call
1072 // `TryInlinePolymorphicCall` even though we are monomorphic.
1073 const bool actually_monomorphic = number_of_types == 1;
1074 DCHECK_IMPLIES(actually_monomorphic, UseOnlyPolymorphicInliningWithNoDeopt());
1075
1076 // We only want to limit recursive polymorphic cases, not monomorphic ones.
1077 const bool too_many_polymorphic_recursive_calls =
1078 !actually_monomorphic &&
1079 CountRecursiveCallsOf(method) > kMaximumNumberOfPolymorphicRecursiveCalls;
1080 if (too_many_polymorphic_recursive_calls) {
1081 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedPolymorphicRecursiveBudget)
1082 << "Method " << method->PrettyMethod()
1083 << " is not inlined because it has reached its polymorphic recursive call budget.";
1084 } else if (class_index.IsValid()) {
1085 LOG_NOTE() << "Try inline polymorphic call to " << method->PrettyMethod();
1086 }
1087
1088 if (too_many_polymorphic_recursive_calls ||
1089 !class_index.IsValid() ||
1090 !TryBuildAndInline(invoke_instruction,
1091 method,
1092 ReferenceTypeInfo::Create(handle, /* is_exact= */ true),
1093 &return_replacement,
1094 /* is_speculative= */ true)) {
1095 all_targets_inlined = false;
1096 } else {
1097 one_target_inlined = true;
1098
1099 LOG_SUCCESS() << "Polymorphic call to "
1100 << invoke_instruction->GetMethodReference().PrettyMethod()
1101 << " has inlined " << ArtMethod::PrettyMethod(method);
1102
1103 // If we have inlined all targets before, and this receiver is the last seen,
1104 // we deoptimize instead of keeping the original invoke instruction.
1105 bool deoptimize = !UseOnlyPolymorphicInliningWithNoDeopt() &&
1106 all_targets_inlined &&
1107 (i + 1 == number_of_types);
1108
1109 HInstruction* compare = AddTypeGuard(receiver,
1110 cursor,
1111 bb_cursor,
1112 class_index,
1113 handle,
1114 invoke_instruction,
1115 deoptimize);
1116 if (deoptimize) {
1117 MaybeReplaceAndRemove(return_replacement, invoke_instruction);
1118 } else {
1119 CreateDiamondPatternForPolymorphicInline(compare, return_replacement, invoke_instruction);
1120 }
1121 }
1122 }
1123
1124 if (!one_target_inlined) {
1125 LOG_FAIL_NO_STAT()
1126 << "Call to " << invoke_instruction->GetMethodReference().PrettyMethod()
1127 << " from inline cache is not inlined because none"
1128 << " of its targets could be inlined";
1129 return false;
1130 }
1131
1132 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedPolymorphicCall);
1133
1134 // Lazily run type propagation to get the guards typed.
1135 run_extra_type_propagation_ = true;
1136 return true;
1137 }
1138
CreateDiamondPatternForPolymorphicInline(HInstruction * compare,HInstruction * return_replacement,HInstruction * invoke_instruction)1139 void HInliner::CreateDiamondPatternForPolymorphicInline(HInstruction* compare,
1140 HInstruction* return_replacement,
1141 HInstruction* invoke_instruction) {
1142 uint32_t dex_pc = invoke_instruction->GetDexPc();
1143 HBasicBlock* cursor_block = compare->GetBlock();
1144 HBasicBlock* original_invoke_block = invoke_instruction->GetBlock();
1145 ArenaAllocator* allocator = graph_->GetAllocator();
1146
1147 // Spit the block after the compare: `cursor_block` will now be the start of the diamond,
1148 // and the returned block is the start of the then branch (that could contain multiple blocks).
1149 HBasicBlock* then = cursor_block->SplitAfterForInlining(compare);
1150
1151 // Split the block containing the invoke before and after the invoke. The returned block
1152 // of the split before will contain the invoke and will be the otherwise branch of
1153 // the diamond. The returned block of the split after will be the merge block
1154 // of the diamond.
1155 HBasicBlock* end_then = invoke_instruction->GetBlock();
1156 HBasicBlock* otherwise = end_then->SplitBeforeForInlining(invoke_instruction);
1157 HBasicBlock* merge = otherwise->SplitAfterForInlining(invoke_instruction);
1158
1159 // If the methods we are inlining return a value, we create a phi in the merge block
1160 // that will have the `invoke_instruction and the `return_replacement` as inputs.
1161 if (return_replacement != nullptr) {
1162 HPhi* phi = new (allocator) HPhi(
1163 allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke_instruction->GetType()), dex_pc);
1164 merge->AddPhi(phi);
1165 invoke_instruction->ReplaceWith(phi);
1166 phi->AddInput(return_replacement);
1167 phi->AddInput(invoke_instruction);
1168 }
1169
1170 // Add the control flow instructions.
1171 otherwise->AddInstruction(new (allocator) HGoto(dex_pc));
1172 end_then->AddInstruction(new (allocator) HGoto(dex_pc));
1173 cursor_block->AddInstruction(new (allocator) HIf(compare, dex_pc));
1174
1175 // Add the newly created blocks to the graph.
1176 graph_->AddBlock(then);
1177 graph_->AddBlock(otherwise);
1178 graph_->AddBlock(merge);
1179
1180 // Set up successor (and implictly predecessor) relations.
1181 cursor_block->AddSuccessor(otherwise);
1182 cursor_block->AddSuccessor(then);
1183 end_then->AddSuccessor(merge);
1184 otherwise->AddSuccessor(merge);
1185
1186 // Set up dominance information.
1187 then->SetDominator(cursor_block);
1188 cursor_block->AddDominatedBlock(then);
1189 otherwise->SetDominator(cursor_block);
1190 cursor_block->AddDominatedBlock(otherwise);
1191 merge->SetDominator(cursor_block);
1192 cursor_block->AddDominatedBlock(merge);
1193
1194 // Update the revert post order.
1195 size_t index = IndexOfElement(graph_->reverse_post_order_, cursor_block);
1196 MakeRoomFor(&graph_->reverse_post_order_, 1, index);
1197 graph_->reverse_post_order_[++index] = then;
1198 index = IndexOfElement(graph_->reverse_post_order_, end_then);
1199 MakeRoomFor(&graph_->reverse_post_order_, 2, index);
1200 graph_->reverse_post_order_[++index] = otherwise;
1201 graph_->reverse_post_order_[++index] = merge;
1202
1203
1204 graph_->UpdateLoopAndTryInformationOfNewBlock(
1205 then, original_invoke_block, /* replace_if_back_edge= */ false);
1206 graph_->UpdateLoopAndTryInformationOfNewBlock(
1207 otherwise, original_invoke_block, /* replace_if_back_edge= */ false);
1208
1209 // In case the original invoke location was a back edge, we need to update
1210 // the loop to now have the merge block as a back edge.
1211 graph_->UpdateLoopAndTryInformationOfNewBlock(
1212 merge, original_invoke_block, /* replace_if_back_edge= */ true);
1213 }
1214
TryInlinePolymorphicCallToSameTarget(HInvoke * invoke_instruction,const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)1215 bool HInliner::TryInlinePolymorphicCallToSameTarget(
1216 HInvoke* invoke_instruction,
1217 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
1218 // This optimization only works under JIT for now.
1219 if (!codegen_->GetCompilerOptions().IsJitCompiler()) {
1220 return false;
1221 }
1222
1223 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
1224 PointerSize pointer_size = class_linker->GetImagePointerSize();
1225
1226 ArtMethod* actual_method = nullptr;
1227 size_t method_index = invoke_instruction->IsInvokeVirtual()
1228 ? invoke_instruction->AsInvokeVirtual()->GetVTableIndex()
1229 : invoke_instruction->AsInvokeInterface()->GetImtIndex();
1230
1231 // Check whether we are actually calling the same method among
1232 // the different types seen.
1233 DCHECK_EQ(classes.Capacity(), InlineCache::kIndividualCacheSize);
1234 uint8_t number_of_types = classes.Size();
1235 for (size_t i = 0; i != number_of_types; ++i) {
1236 DCHECK(classes.GetReference(i) != nullptr);
1237 ArtMethod* new_method = nullptr;
1238 if (invoke_instruction->IsInvokeInterface()) {
1239 new_method = classes.GetReference(i)->AsClass()->GetImt(pointer_size)->Get(
1240 method_index, pointer_size);
1241 if (new_method->IsRuntimeMethod()) {
1242 // Bail out as soon as we see a conflict trampoline in one of the target's
1243 // interface table.
1244 return false;
1245 }
1246 } else {
1247 DCHECK(invoke_instruction->IsInvokeVirtual());
1248 new_method =
1249 classes.GetReference(i)->AsClass()->GetEmbeddedVTableEntry(method_index, pointer_size);
1250 }
1251 DCHECK(new_method != nullptr);
1252 if (actual_method == nullptr) {
1253 actual_method = new_method;
1254 } else if (actual_method != new_method) {
1255 // Different methods, bailout.
1256 return false;
1257 }
1258 }
1259
1260 HInstruction* receiver = invoke_instruction->InputAt(0);
1261 HInstruction* cursor = invoke_instruction->GetPrevious();
1262 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
1263
1264 HInstruction* return_replacement = nullptr;
1265 Handle<mirror::Class> cls =
1266 graph_->GetHandleCache()->NewHandle(actual_method->GetDeclaringClass());
1267 if (!TryBuildAndInline(invoke_instruction,
1268 actual_method,
1269 ReferenceTypeInfo::Create(cls),
1270 &return_replacement,
1271 /* is_speculative= */ true)) {
1272 return false;
1273 }
1274
1275 // We successfully inlined, now add a guard.
1276 HInstanceFieldGet* receiver_class = BuildGetReceiverClass(
1277 receiver, invoke_instruction->GetDexPc());
1278
1279 DataType::Type type = Is64BitInstructionSet(graph_->GetInstructionSet())
1280 ? DataType::Type::kInt64
1281 : DataType::Type::kInt32;
1282 HClassTableGet* class_table_get = new (graph_->GetAllocator()) HClassTableGet(
1283 receiver_class,
1284 type,
1285 invoke_instruction->IsInvokeVirtual() ? HClassTableGet::TableKind::kVTable
1286 : HClassTableGet::TableKind::kIMTable,
1287 method_index,
1288 invoke_instruction->GetDexPc());
1289
1290 HConstant* constant;
1291 if (type == DataType::Type::kInt64) {
1292 constant = graph_->GetLongConstant(reinterpret_cast<intptr_t>(actual_method));
1293 } else {
1294 constant = graph_->GetIntConstant(reinterpret_cast<intptr_t>(actual_method));
1295 }
1296
1297 HNotEqual* compare = new (graph_->GetAllocator()) HNotEqual(class_table_get, constant);
1298 if (cursor != nullptr) {
1299 bb_cursor->InsertInstructionAfter(receiver_class, cursor);
1300 } else {
1301 bb_cursor->InsertInstructionBefore(receiver_class, bb_cursor->GetFirstInstruction());
1302 }
1303 bb_cursor->InsertInstructionAfter(class_table_get, receiver_class);
1304 bb_cursor->InsertInstructionAfter(compare, class_table_get);
1305
1306 if (outermost_graph_->IsCompilingOsr()) {
1307 CreateDiamondPatternForPolymorphicInline(compare, return_replacement, invoke_instruction);
1308 } else {
1309 HDeoptimize* deoptimize = new (graph_->GetAllocator()) HDeoptimize(
1310 graph_->GetAllocator(),
1311 compare,
1312 receiver,
1313 DeoptimizationKind::kJitSameTarget,
1314 invoke_instruction->GetDexPc());
1315 bb_cursor->InsertInstructionAfter(deoptimize, compare);
1316 deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1317 MaybeReplaceAndRemove(return_replacement, invoke_instruction);
1318 receiver->ReplaceUsesDominatedBy(deoptimize, deoptimize);
1319 deoptimize->SetReferenceTypeInfo(receiver->GetReferenceTypeInfo());
1320 }
1321
1322 // Lazily run type propagation to get the guard typed.
1323 run_extra_type_propagation_ = true;
1324 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedPolymorphicCall);
1325
1326 LOG_SUCCESS() << "Inlined same polymorphic target " << actual_method->PrettyMethod();
1327 return true;
1328 }
1329
MaybeRunReferenceTypePropagation(HInstruction * replacement,HInvoke * invoke_instruction)1330 void HInliner::MaybeRunReferenceTypePropagation(HInstruction* replacement,
1331 HInvoke* invoke_instruction) {
1332 if (ReturnTypeMoreSpecific(replacement, invoke_instruction)) {
1333 // Actual return value has a more specific type than the method's declared
1334 // return type. Run RTP again on the outer graph to propagate it.
1335 ReferenceTypePropagation(graph_,
1336 outer_compilation_unit_.GetDexCache(),
1337 /* is_first_run= */ false).Run();
1338 }
1339 }
1340
TryDevirtualize(HInvoke * invoke_instruction,ArtMethod * method,HInvoke ** replacement)1341 bool HInliner::TryDevirtualize(HInvoke* invoke_instruction,
1342 ArtMethod* method,
1343 HInvoke** replacement) {
1344 DCHECK(invoke_instruction != *replacement);
1345 if (!invoke_instruction->IsInvokeInterface() && !invoke_instruction->IsInvokeVirtual()) {
1346 return false;
1347 }
1348
1349 // Don't devirtualize to an intrinsic invalid after the builder phase. The ArtMethod might be an
1350 // intrinsic even when the HInvoke isn't e.g. java.lang.CharSequence.isEmpty (not an intrinsic)
1351 // can get devirtualized into java.lang.String.isEmpty (which is an intrinsic).
1352 if (method->IsIntrinsic() && !IsValidIntrinsicAfterBuilder(method->GetIntrinsic())) {
1353 return false;
1354 }
1355
1356 // Don't bother trying to call directly a default conflict method. It
1357 // doesn't have a proper MethodReference, but also `GetCanonicalMethod`
1358 // will return an actual default implementation.
1359 if (method->IsDefaultConflicting()) {
1360 return false;
1361 }
1362 DCHECK(!method->IsProxyMethod());
1363 ClassLinker* cl = Runtime::Current()->GetClassLinker();
1364 PointerSize pointer_size = cl->GetImagePointerSize();
1365 // The sharpening logic assumes the caller isn't passing a copied method.
1366 method = method->GetCanonicalMethod(pointer_size);
1367 uint32_t dex_method_index = FindMethodIndexIn(
1368 method,
1369 *invoke_instruction->GetMethodReference().dex_file,
1370 invoke_instruction->GetMethodReference().index);
1371 if (dex_method_index == dex::kDexNoIndex) {
1372 return false;
1373 }
1374 HInvokeStaticOrDirect::DispatchInfo dispatch_info =
1375 HSharpening::SharpenLoadMethod(method,
1376 /* has_method_id= */ true,
1377 /* for_interface_call= */ false,
1378 codegen_);
1379 DCHECK_NE(dispatch_info.code_ptr_location, CodePtrLocation::kCallCriticalNative);
1380 if (dispatch_info.method_load_kind == MethodLoadKind::kRuntimeCall) {
1381 // If sharpening returns that we need to load the method at runtime, keep
1382 // the virtual/interface call which will be faster.
1383 // Also, the entrypoints for runtime calls do not handle devirtualized
1384 // calls.
1385 return false;
1386 }
1387
1388 HInvokeStaticOrDirect* new_invoke = new (graph_->GetAllocator()) HInvokeStaticOrDirect(
1389 graph_->GetAllocator(),
1390 invoke_instruction->GetNumberOfArguments(),
1391 invoke_instruction->GetNumberOfOutVRegs(),
1392 invoke_instruction->GetType(),
1393 invoke_instruction->GetDexPc(),
1394 MethodReference(invoke_instruction->GetMethodReference().dex_file, dex_method_index),
1395 method,
1396 dispatch_info,
1397 kDirect,
1398 MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
1399 HInvokeStaticOrDirect::ClinitCheckRequirement::kNone,
1400 !graph_->IsDebuggable());
1401 HInputsRef inputs = invoke_instruction->GetInputs();
1402 DCHECK_EQ(inputs.size(), invoke_instruction->GetNumberOfArguments());
1403 for (size_t index = 0; index != inputs.size(); ++index) {
1404 new_invoke->SetArgumentAt(index, inputs[index]);
1405 }
1406 if (HInvokeStaticOrDirect::NeedsCurrentMethodInput(dispatch_info)) {
1407 new_invoke->SetRawInputAt(new_invoke->GetCurrentMethodIndexUnchecked(),
1408 graph_->GetCurrentMethod());
1409 }
1410 invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
1411 new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1412 if (invoke_instruction->GetType() == DataType::Type::kReference) {
1413 new_invoke->SetReferenceTypeInfoIfValid(invoke_instruction->GetReferenceTypeInfo());
1414 }
1415 *replacement = new_invoke;
1416
1417 MaybeReplaceAndRemove(*replacement, invoke_instruction);
1418 // No need to call MaybeRunReferenceTypePropagation, as we know the return type
1419 // cannot be more specific.
1420 DCHECK(!ReturnTypeMoreSpecific(*replacement, invoke_instruction));
1421 return true;
1422 }
1423
1424
TryInlineAndReplace(HInvoke * invoke_instruction,ArtMethod * method,ReferenceTypeInfo receiver_type,bool do_rtp,bool is_speculative)1425 bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction,
1426 ArtMethod* method,
1427 ReferenceTypeInfo receiver_type,
1428 bool do_rtp,
1429 bool is_speculative) {
1430 DCHECK(!codegen_->IsImplementedIntrinsic(invoke_instruction));
1431 HInstruction* return_replacement = nullptr;
1432
1433 if (!TryBuildAndInline(
1434 invoke_instruction, method, receiver_type, &return_replacement, is_speculative)) {
1435 return false;
1436 }
1437
1438 MaybeReplaceAndRemove(return_replacement, invoke_instruction);
1439 FixUpReturnReferenceType(method, return_replacement);
1440 if (do_rtp) {
1441 MaybeRunReferenceTypePropagation(return_replacement, invoke_instruction);
1442 }
1443 return true;
1444 }
1445
CountRecursiveCallsOf(ArtMethod * method) const1446 size_t HInliner::CountRecursiveCallsOf(ArtMethod* method) const {
1447 const HInliner* current = this;
1448 size_t count = 0;
1449 do {
1450 if (current->graph_->GetArtMethod() == method) {
1451 ++count;
1452 }
1453 current = current->parent_;
1454 } while (current != nullptr);
1455 return count;
1456 }
1457
MayInline(const CompilerOptions & compiler_options,const DexFile & inlined_from,const DexFile & inlined_into)1458 static inline bool MayInline(const CompilerOptions& compiler_options,
1459 const DexFile& inlined_from,
1460 const DexFile& inlined_into) {
1461 // We're not allowed to inline across dex files if we're the no-inline-from dex file.
1462 if (!IsSameDexFile(inlined_from, inlined_into) &&
1463 ContainsElement(compiler_options.GetNoInlineFromDexFile(), &inlined_from)) {
1464 return false;
1465 }
1466
1467 return true;
1468 }
1469
1470 // Returns whether inlining is allowed based on ART semantics.
IsInliningAllowed(ArtMethod * method,const CodeItemDataAccessor & accessor) const1471 bool HInliner::IsInliningAllowed(ArtMethod* method, const CodeItemDataAccessor& accessor) const {
1472 if (!accessor.HasCodeItem()) {
1473 LOG_FAIL_NO_STAT()
1474 << "Method " << method->PrettyMethod() << " is not inlined because it is native";
1475 return false;
1476 }
1477
1478 if (!method->IsCompilable()) {
1479 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotCompilable)
1480 << "Method " << method->PrettyMethod()
1481 << " has soft failures un-handled by the compiler, so it cannot be inlined";
1482 return false;
1483 }
1484
1485 if (!IsMethodVerified(method)) {
1486 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified)
1487 << "Method " << method->PrettyMethod()
1488 << " couldn't be verified, so it cannot be inlined";
1489 return false;
1490 }
1491
1492 if (annotations::MethodIsNeverInline(*method->GetDexFile(),
1493 method->GetClassDef(),
1494 method->GetDexMethodIndex())) {
1495 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNeverInlineAnnotation)
1496 << "Method " << method->PrettyMethod()
1497 << " has the @NeverInline annotation so it won't be inlined";
1498 return false;
1499 }
1500
1501 return true;
1502 }
1503
1504 // Returns whether ART supports inlining this method.
1505 //
1506 // Some methods are not supported because they have features for which inlining
1507 // is not implemented. For example, we do not currently support inlining throw
1508 // instructions into a try block.
IsInliningSupported(const HInvoke * invoke_instruction,ArtMethod * method,const CodeItemDataAccessor & accessor) const1509 bool HInliner::IsInliningSupported(const HInvoke* invoke_instruction,
1510 ArtMethod* method,
1511 const CodeItemDataAccessor& accessor) const {
1512 if (method->IsProxyMethod()) {
1513 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedProxy)
1514 << "Method " << method->PrettyMethod()
1515 << " is not inlined because of unimplemented inline support for proxy methods.";
1516 return false;
1517 }
1518
1519 if (accessor.TriesSize() != 0) {
1520 if (!kInlineTryCatches) {
1521 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatchDisabled)
1522 << "Method " << method->PrettyMethod()
1523 << " is not inlined because inlining try catches is disabled globally";
1524 return false;
1525 }
1526 const bool disallowed_try_catch_inlining =
1527 // Direct parent is a try block.
1528 invoke_instruction->GetBlock()->IsTryBlock() ||
1529 // Indirect parent disallows try catch inlining.
1530 !try_catch_inlining_allowed_;
1531 if (disallowed_try_catch_inlining) {
1532 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatchCallee)
1533 << "Method " << method->PrettyMethod()
1534 << " is not inlined because it has a try catch and we are not supporting it for this"
1535 << " particular call. This is could be because e.g. it would be inlined inside another"
1536 << " try block, we arrived here from TryInlinePolymorphicCall, etc.";
1537 return false;
1538 }
1539 }
1540
1541 if (invoke_instruction->IsInvokeStaticOrDirect() &&
1542 invoke_instruction->AsInvokeStaticOrDirect()->IsStaticWithImplicitClinitCheck()) {
1543 // Case of a static method that cannot be inlined because it implicitly
1544 // requires an initialization check of its declaring class.
1545 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedDexCacheClinitCheck)
1546 << "Method " << method->PrettyMethod()
1547 << " is not inlined because it is static and requires a clinit"
1548 << " check that cannot be emitted due to Dex cache limitations";
1549 return false;
1550 }
1551
1552 return true;
1553 }
1554
IsInliningEncouraged(const HInvoke * invoke_instruction,ArtMethod * method,const CodeItemDataAccessor & accessor) const1555 bool HInliner::IsInliningEncouraged(const HInvoke* invoke_instruction,
1556 ArtMethod* method,
1557 const CodeItemDataAccessor& accessor) const {
1558 if (CountRecursiveCallsOf(method) > kMaximumNumberOfRecursiveCalls) {
1559 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedRecursiveBudget)
1560 << "Method "
1561 << method->PrettyMethod()
1562 << " is not inlined because it has reached its recursive call budget.";
1563 return false;
1564 }
1565
1566 size_t inline_max_code_units = codegen_->GetCompilerOptions().GetInlineMaxCodeUnits();
1567 if (accessor.InsnsSizeInCodeUnits() > inline_max_code_units) {
1568 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCodeItem)
1569 << "Method " << method->PrettyMethod()
1570 << " is not inlined because its code item is too big: "
1571 << accessor.InsnsSizeInCodeUnits()
1572 << " > "
1573 << inline_max_code_units;
1574 return false;
1575 }
1576
1577 if (graph_->IsCompilingBaseline() &&
1578 accessor.InsnsSizeInCodeUnits() > CompilerOptions::kBaselineInlineMaxCodeUnits) {
1579 LOG_FAIL_NO_STAT() << "Reached baseline maximum code unit for inlining "
1580 << method->PrettyMethod();
1581 outermost_graph_->SetUsefulOptimizing();
1582 return false;
1583 }
1584
1585 if (invoke_instruction->GetBlock()->GetLastInstruction()->IsThrow()) {
1586 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedEndsWithThrow)
1587 << "Method " << method->PrettyMethod()
1588 << " is not inlined because its block ends with a throw";
1589 return false;
1590 }
1591
1592 return true;
1593 }
1594
TryBuildAndInline(HInvoke * invoke_instruction,ArtMethod * method,ReferenceTypeInfo receiver_type,HInstruction ** return_replacement,bool is_speculative)1595 bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
1596 ArtMethod* method,
1597 ReferenceTypeInfo receiver_type,
1598 HInstruction** return_replacement,
1599 bool is_speculative) {
1600 DCHECK_IMPLIES(method->IsStatic(), !receiver_type.IsValid());
1601 DCHECK_IMPLIES(!method->IsStatic(), receiver_type.IsValid());
1602 // If invoke_instruction is devirtualized to a different method, give intrinsics
1603 // another chance before we try to inline it.
1604 if (invoke_instruction->GetResolvedMethod() != method &&
1605 method->IsIntrinsic() &&
1606 IsValidIntrinsicAfterBuilder(method->GetIntrinsic())) {
1607 MaybeRecordStat(stats_, MethodCompilationStat::kIntrinsicRecognized);
1608 // For simplicity, always create a new instruction to replace the existing
1609 // invoke.
1610 HInvokeVirtual* new_invoke = new (graph_->GetAllocator()) HInvokeVirtual(
1611 graph_->GetAllocator(),
1612 invoke_instruction->GetNumberOfArguments(),
1613 invoke_instruction->GetNumberOfOutVRegs(),
1614 invoke_instruction->GetType(),
1615 invoke_instruction->GetDexPc(),
1616 invoke_instruction->GetMethodReference(), // Use existing invoke's method's reference.
1617 method,
1618 MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
1619 method->GetMethodIndex(),
1620 !graph_->IsDebuggable());
1621 DCHECK_NE(new_invoke->GetIntrinsic(), Intrinsics::kNone);
1622 HInputsRef inputs = invoke_instruction->GetInputs();
1623 for (size_t index = 0; index != inputs.size(); ++index) {
1624 new_invoke->SetArgumentAt(index, inputs[index]);
1625 }
1626 invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
1627 new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1628 if (invoke_instruction->GetType() == DataType::Type::kReference) {
1629 new_invoke->SetReferenceTypeInfoIfValid(invoke_instruction->GetReferenceTypeInfo());
1630 }
1631 *return_replacement = new_invoke;
1632 return true;
1633 }
1634
1635 CodeItemDataAccessor accessor(method->DexInstructionData());
1636
1637 if (!IsInliningAllowed(method, accessor)) {
1638 return false;
1639 }
1640
1641 // We have checked above that inlining is "allowed" to make sure that the method has bytecode
1642 // (is not native), is compilable and verified and to enforce the @NeverInline annotation.
1643 // However, the pattern substitution is always preferable, so we do it before the check if
1644 // inlining is "encouraged". It also has an exception to the `MayInline()` restriction.
1645 if (TryPatternSubstitution(invoke_instruction, method, accessor, return_replacement)) {
1646 LOG_SUCCESS() << "Successfully replaced pattern of invoke "
1647 << method->PrettyMethod();
1648 MaybeRecordStat(stats_, MethodCompilationStat::kReplacedInvokeWithSimplePattern);
1649 return true;
1650 }
1651
1652 // Check whether we're allowed to inline. The outermost compilation unit is the relevant
1653 // dex file here (though the transitivity of an inline chain would allow checking the caller).
1654 if (!MayInline(codegen_->GetCompilerOptions(),
1655 *method->GetDexFile(),
1656 *outer_compilation_unit_.GetDexFile())) {
1657 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedWont)
1658 << "Won't inline " << method->PrettyMethod() << " in "
1659 << outer_compilation_unit_.GetDexFile()->GetLocation() << " ("
1660 << caller_compilation_unit_.GetDexFile()->GetLocation() << ") from "
1661 << method->GetDexFile()->GetLocation();
1662 return false;
1663 }
1664
1665 if (!IsInliningSupported(invoke_instruction, method, accessor)) {
1666 return false;
1667 }
1668
1669 if (!IsInliningEncouraged(invoke_instruction, method, accessor)) {
1670 return false;
1671 }
1672
1673 if (!TryBuildAndInlineHelper(
1674 invoke_instruction, method, receiver_type, return_replacement, is_speculative)) {
1675 return false;
1676 }
1677
1678 LOG_SUCCESS() << method->PrettyMethod();
1679 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvoke);
1680 if (outermost_graph_ == graph_) {
1681 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedLastInvoke);
1682 }
1683 return true;
1684 }
1685
GetInvokeInputForArgVRegIndex(HInvoke * invoke_instruction,size_t arg_vreg_index)1686 static HInstruction* GetInvokeInputForArgVRegIndex(HInvoke* invoke_instruction,
1687 size_t arg_vreg_index)
1688 REQUIRES_SHARED(Locks::mutator_lock_) {
1689 size_t input_index = 0;
1690 for (size_t i = 0; i < arg_vreg_index; ++i, ++input_index) {
1691 DCHECK_LT(input_index, invoke_instruction->GetNumberOfArguments());
1692 if (DataType::Is64BitType(invoke_instruction->InputAt(input_index)->GetType())) {
1693 ++i;
1694 DCHECK_NE(i, arg_vreg_index);
1695 }
1696 }
1697 DCHECK_LT(input_index, invoke_instruction->GetNumberOfArguments());
1698 return invoke_instruction->InputAt(input_index);
1699 }
1700
1701 // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
TryPatternSubstitution(HInvoke * invoke_instruction,ArtMethod * method,const CodeItemDataAccessor & accessor,HInstruction ** return_replacement)1702 bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
1703 ArtMethod* method,
1704 const CodeItemDataAccessor& accessor,
1705 HInstruction** return_replacement) {
1706 InlineMethod inline_method;
1707 if (!InlineMethodAnalyser::AnalyseMethodCode(method, &accessor, &inline_method)) {
1708 return false;
1709 }
1710
1711 size_t number_of_instructions = 0u; // Note: We do not count constants.
1712 switch (inline_method.opcode) {
1713 case kInlineOpNop:
1714 DCHECK_EQ(invoke_instruction->GetType(), DataType::Type::kVoid);
1715 *return_replacement = nullptr;
1716 break;
1717 case kInlineOpReturnArg:
1718 *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction,
1719 inline_method.d.return_data.arg);
1720 break;
1721 case kInlineOpNonWideConst: {
1722 char shorty0 = method->GetShorty()[0];
1723 if (shorty0 == 'L') {
1724 DCHECK_EQ(inline_method.d.data, 0u);
1725 *return_replacement = graph_->GetNullConstant();
1726 } else if (shorty0 == 'F') {
1727 *return_replacement = graph_->GetFloatConstant(
1728 bit_cast<float, int32_t>(static_cast<int32_t>(inline_method.d.data)));
1729 } else {
1730 *return_replacement = graph_->GetIntConstant(static_cast<int32_t>(inline_method.d.data));
1731 }
1732 break;
1733 }
1734 case kInlineOpIGet: {
1735 const InlineIGetIPutData& data = inline_method.d.ifield_data;
1736 if (data.method_is_static || data.object_arg != 0u) {
1737 // TODO: Needs null check.
1738 return false;
1739 }
1740 HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
1741 HInstanceFieldGet* iget = CreateInstanceFieldGet(data.field_idx, method, obj);
1742 DCHECK_EQ(iget->GetFieldOffset().Uint32Value(), data.field_offset);
1743 DCHECK_EQ(iget->IsVolatile() ? 1u : 0u, data.is_volatile);
1744 invoke_instruction->GetBlock()->InsertInstructionBefore(iget, invoke_instruction);
1745 *return_replacement = iget;
1746 number_of_instructions = 1u;
1747 break;
1748 }
1749 case kInlineOpIPut: {
1750 const InlineIGetIPutData& data = inline_method.d.ifield_data;
1751 if (data.method_is_static || data.object_arg != 0u) {
1752 // TODO: Needs null check.
1753 return false;
1754 }
1755 HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
1756 HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, data.src_arg);
1757 HInstanceFieldSet* iput = CreateInstanceFieldSet(data.field_idx, method, obj, value);
1758 DCHECK_EQ(iput->GetFieldOffset().Uint32Value(), data.field_offset);
1759 DCHECK_EQ(iput->IsVolatile() ? 1u : 0u, data.is_volatile);
1760 invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
1761 if (data.return_arg_plus1 != 0u) {
1762 size_t return_arg = data.return_arg_plus1 - 1u;
1763 *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction, return_arg);
1764 }
1765 number_of_instructions = 1u;
1766 break;
1767 }
1768 case kInlineOpConstructor: {
1769 const InlineConstructorData& data = inline_method.d.constructor_data;
1770 // Get the indexes to arrays for easier processing.
1771 uint16_t iput_field_indexes[] = {
1772 data.iput0_field_index, data.iput1_field_index, data.iput2_field_index
1773 };
1774 uint16_t iput_args[] = { data.iput0_arg, data.iput1_arg, data.iput2_arg };
1775 static_assert(arraysize(iput_args) == arraysize(iput_field_indexes), "Size mismatch");
1776 // Count valid field indexes.
1777 for (size_t i = 0, end = data.iput_count; i < end; i++) {
1778 // Check that there are no duplicate valid field indexes.
1779 DCHECK_EQ(0, std::count(iput_field_indexes + i + 1,
1780 iput_field_indexes + end,
1781 iput_field_indexes[i]));
1782 }
1783 // Check that there are no valid field indexes in the rest of the array.
1784 DCHECK_EQ(0, std::count_if(iput_field_indexes + data.iput_count,
1785 iput_field_indexes + arraysize(iput_field_indexes),
1786 [](uint16_t index) { return index != DexFile::kDexNoIndex16; }));
1787
1788 // Create HInstanceFieldSet for each IPUT that stores non-zero data.
1789 HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction,
1790 /* arg_vreg_index= */ 0u);
1791 bool needs_constructor_barrier = false;
1792 for (size_t i = 0, end = data.iput_count; i != end; ++i) {
1793 HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, iput_args[i]);
1794 if (!IsZeroBitPattern(value)) {
1795 uint16_t field_index = iput_field_indexes[i];
1796 bool is_final;
1797 HInstanceFieldSet* iput =
1798 CreateInstanceFieldSet(field_index, method, obj, value, &is_final);
1799 invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
1800
1801 // Check whether the field is final. If it is, we need to add a barrier.
1802 if (is_final) {
1803 needs_constructor_barrier = true;
1804 }
1805 }
1806 }
1807 if (needs_constructor_barrier) {
1808 // See DexCompilationUnit::RequiresConstructorBarrier for more details.
1809 DCHECK(obj != nullptr) << "only non-static methods can have a constructor fence";
1810
1811 HConstructorFence* constructor_fence =
1812 new (graph_->GetAllocator()) HConstructorFence(obj, kNoDexPc, graph_->GetAllocator());
1813 invoke_instruction->GetBlock()->InsertInstructionBefore(constructor_fence,
1814 invoke_instruction);
1815 }
1816 *return_replacement = nullptr;
1817 number_of_instructions = data.iput_count + (needs_constructor_barrier ? 1u : 0u);
1818 break;
1819 }
1820 }
1821 if (number_of_instructions != 0u) {
1822 total_number_of_instructions_ += number_of_instructions;
1823 UpdateInliningBudget();
1824 }
1825 return true;
1826 }
1827
CreateInstanceFieldGet(uint32_t field_index,ArtMethod * referrer,HInstruction * obj)1828 HInstanceFieldGet* HInliner::CreateInstanceFieldGet(uint32_t field_index,
1829 ArtMethod* referrer,
1830 HInstruction* obj)
1831 REQUIRES_SHARED(Locks::mutator_lock_) {
1832 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
1833 ArtField* resolved_field =
1834 class_linker->LookupResolvedField(field_index, referrer, /* is_static= */ false);
1835 DCHECK(resolved_field != nullptr);
1836 HInstanceFieldGet* iget = new (graph_->GetAllocator()) HInstanceFieldGet(
1837 obj,
1838 resolved_field,
1839 DataType::FromShorty(resolved_field->GetTypeDescriptor()[0]),
1840 resolved_field->GetOffset(),
1841 resolved_field->IsVolatile(),
1842 field_index,
1843 resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
1844 *referrer->GetDexFile(),
1845 // Read barrier generates a runtime call in slow path and we need a valid
1846 // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
1847 /* dex_pc= */ 0);
1848 if (iget->GetType() == DataType::Type::kReference) {
1849 // Use the same dex_cache that we used for field lookup as the hint_dex_cache.
1850 Handle<mirror::DexCache> dex_cache =
1851 graph_->GetHandleCache()->NewHandle(referrer->GetDexCache());
1852 ReferenceTypePropagation rtp(graph_,
1853 dex_cache,
1854 /* is_first_run= */ false);
1855 rtp.Visit(iget);
1856 }
1857 return iget;
1858 }
1859
CreateInstanceFieldSet(uint32_t field_index,ArtMethod * referrer,HInstruction * obj,HInstruction * value,bool * is_final)1860 HInstanceFieldSet* HInliner::CreateInstanceFieldSet(uint32_t field_index,
1861 ArtMethod* referrer,
1862 HInstruction* obj,
1863 HInstruction* value,
1864 bool* is_final)
1865 REQUIRES_SHARED(Locks::mutator_lock_) {
1866 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
1867 ArtField* resolved_field =
1868 class_linker->LookupResolvedField(field_index, referrer, /* is_static= */ false);
1869 DCHECK(resolved_field != nullptr);
1870 if (is_final != nullptr) {
1871 // This information is needed only for constructors.
1872 DCHECK(referrer->IsConstructor());
1873 *is_final = resolved_field->IsFinal();
1874 }
1875 HInstanceFieldSet* iput = new (graph_->GetAllocator()) HInstanceFieldSet(
1876 obj,
1877 value,
1878 resolved_field,
1879 DataType::FromShorty(resolved_field->GetTypeDescriptor()[0]),
1880 resolved_field->GetOffset(),
1881 resolved_field->IsVolatile(),
1882 field_index,
1883 resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
1884 *referrer->GetDexFile(),
1885 // Read barrier generates a runtime call in slow path and we need a valid
1886 // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
1887 /* dex_pc= */ 0);
1888 return iput;
1889 }
1890
1891 template <typename T>
NewHandleIfDifferent(ObjPtr<T> object,Handle<T> hint,HGraph * graph)1892 static inline Handle<T> NewHandleIfDifferent(ObjPtr<T> object, Handle<T> hint, HGraph* graph)
1893 REQUIRES_SHARED(Locks::mutator_lock_) {
1894 return (object != hint.Get()) ? graph->GetHandleCache()->NewHandle(object) : hint;
1895 }
1896
CanEncodeInlinedMethodInStackMap(const DexFile & outer_dex_file,ArtMethod * callee,const CodeGenerator * codegen,bool * out_needs_bss_check)1897 static bool CanEncodeInlinedMethodInStackMap(const DexFile& outer_dex_file,
1898 ArtMethod* callee,
1899 const CodeGenerator* codegen,
1900 bool* out_needs_bss_check)
1901 REQUIRES_SHARED(Locks::mutator_lock_) {
1902 if (!Runtime::Current()->IsAotCompiler()) {
1903 // JIT can always encode methods in stack maps.
1904 return true;
1905 }
1906
1907 const DexFile* dex_file = callee->GetDexFile();
1908 if (IsSameDexFile(outer_dex_file, *dex_file)) {
1909 return true;
1910 }
1911
1912 // Inline across dexfiles if the callee's DexFile is:
1913 // 1) in the bootclasspath, or
1914 if (callee->GetDeclaringClass()->IsBootStrapClassLoaded()) {
1915 // In multi-image, each BCP DexFile has their own OatWriter. Since they don't cooperate with
1916 // each other, we request the BSS check for them.
1917 // TODO(solanes, 154012332): Add .bss support for BCP multi-image.
1918 *out_needs_bss_check = codegen->GetCompilerOptions().IsMultiImage();
1919 return true;
1920 }
1921
1922 // 2) is a non-BCP dexfile with the OatFile we are compiling.
1923 if (codegen->GetCompilerOptions().WithinOatFile(dex_file)) {
1924 return true;
1925 }
1926
1927 // TODO(solanes): Support more AOT cases for inlining:
1928 // - methods in class loader context's DexFiles
1929 return false;
1930 }
1931
1932 // Substitutes parameters in the callee graph with their values from the caller.
SubstituteArguments(HGraph * callee_graph,HInvoke * invoke_instruction,ReferenceTypeInfo receiver_type,const DexCompilationUnit & dex_compilation_unit)1933 void HInliner::SubstituteArguments(HGraph* callee_graph,
1934 HInvoke* invoke_instruction,
1935 ReferenceTypeInfo receiver_type,
1936 const DexCompilationUnit& dex_compilation_unit) {
1937 ArtMethod* const resolved_method = callee_graph->GetArtMethod();
1938 size_t parameter_index = 0;
1939 bool run_rtp = false;
1940 for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions());
1941 !instructions.Done();
1942 instructions.Advance()) {
1943 HInstruction* current = instructions.Current();
1944 if (current->IsParameterValue()) {
1945 HInstruction* argument = invoke_instruction->InputAt(parameter_index);
1946 if (argument->IsNullConstant()) {
1947 current->ReplaceWith(callee_graph->GetNullConstant());
1948 } else if (argument->IsIntConstant()) {
1949 current->ReplaceWith(callee_graph->GetIntConstant(argument->AsIntConstant()->GetValue()));
1950 } else if (argument->IsLongConstant()) {
1951 current->ReplaceWith(callee_graph->GetLongConstant(argument->AsLongConstant()->GetValue()));
1952 } else if (argument->IsFloatConstant()) {
1953 current->ReplaceWith(
1954 callee_graph->GetFloatConstant(argument->AsFloatConstant()->GetValue()));
1955 } else if (argument->IsDoubleConstant()) {
1956 current->ReplaceWith(
1957 callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue()));
1958 } else if (argument->GetType() == DataType::Type::kReference) {
1959 if (!resolved_method->IsStatic() && parameter_index == 0 && receiver_type.IsValid()) {
1960 run_rtp = true;
1961 current->SetReferenceTypeInfo(receiver_type);
1962 } else {
1963 current->SetReferenceTypeInfoIfValid(argument->GetReferenceTypeInfo());
1964 }
1965 current->AsParameterValue()->SetCanBeNull(argument->CanBeNull());
1966 }
1967 ++parameter_index;
1968 }
1969 }
1970
1971 // We have replaced formal arguments with actual arguments. If actual types
1972 // are more specific than the declared ones, run RTP again on the inner graph.
1973 if (run_rtp || ArgumentTypesMoreSpecific(invoke_instruction, resolved_method)) {
1974 ReferenceTypePropagation(callee_graph,
1975 dex_compilation_unit.GetDexCache(),
1976 /* is_first_run= */ false).Run();
1977 }
1978 }
1979
1980 // Returns whether we can inline the callee_graph into the target_block.
1981 //
1982 // This performs a combination of semantics checks, compiler support checks, and
1983 // resource limit checks.
1984 //
1985 // If this function returns true, it will also set out_number_of_instructions to
1986 // the number of instructions in the inlined body.
CanInlineBody(const HGraph * callee_graph,HInvoke * invoke,size_t * out_number_of_instructions,bool is_speculative) const1987 bool HInliner::CanInlineBody(const HGraph* callee_graph,
1988 HInvoke* invoke,
1989 size_t* out_number_of_instructions,
1990 bool is_speculative) const {
1991 ArtMethod* const resolved_method = callee_graph->GetArtMethod();
1992
1993 HBasicBlock* exit_block = callee_graph->GetExitBlock();
1994 if (exit_block == nullptr) {
1995 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInfiniteLoop)
1996 << "Method " << resolved_method->PrettyMethod()
1997 << " could not be inlined because it has an infinite loop";
1998 return false;
1999 }
2000
2001 bool has_one_return = false;
2002 bool has_try_catch = false;
2003 for (HBasicBlock* predecessor : exit_block->GetPredecessors()) {
2004 const HInstruction* last_instruction = predecessor->GetLastInstruction();
2005 // On inlinees, we can have Return/ReturnVoid/Throw -> TryBoundary -> Exit. To check for the
2006 // actual last instruction, we have to skip the TryBoundary instruction.
2007 if (last_instruction->IsTryBoundary()) {
2008 has_try_catch = true;
2009 predecessor = predecessor->GetSinglePredecessor();
2010 last_instruction = predecessor->GetLastInstruction();
2011
2012 // If the last instruction chain is Return/ReturnVoid -> TryBoundary -> Exit we will have to
2013 // split a critical edge in InlineInto and might recompute loop information, which is
2014 // unsupported for irreducible loops.
2015 if (!last_instruction->IsThrow() && graph_->HasIrreducibleLoops()) {
2016 DCHECK(last_instruction->IsReturn() || last_instruction->IsReturnVoid());
2017 // TODO(ngeoffray): Support re-computing loop information to graphs with
2018 // irreducible loops?
2019 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedIrreducibleLoopCaller)
2020 << "Method " << resolved_method->PrettyMethod()
2021 << " could not be inlined because we will have to recompute the loop information and"
2022 << " the caller has irreducible loops";
2023 return false;
2024 }
2025 }
2026
2027 if (last_instruction->IsThrow()) {
2028 if (graph_->GetExitBlock() == nullptr) {
2029 // TODO(ngeoffray): Support adding HExit in the caller graph.
2030 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInfiniteLoop)
2031 << "Method " << resolved_method->PrettyMethod()
2032 << " could not be inlined because one branch always throws and"
2033 << " caller does not have an exit block";
2034 return false;
2035 } else if (graph_->HasIrreducibleLoops()) {
2036 // TODO(ngeoffray): Support re-computing loop information to graphs with
2037 // irreducible loops?
2038 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedIrreducibleLoopCaller)
2039 << "Method " << resolved_method->PrettyMethod()
2040 << " could not be inlined because one branch always throws and"
2041 << " the caller has irreducible loops";
2042 return false;
2043 }
2044 } else {
2045 has_one_return = true;
2046 }
2047 }
2048
2049 if (!has_one_return) {
2050 // If a method has a try catch, all throws are potentially caught. We are conservative and
2051 // don't assume a method always throws unless we can guarantee that.
2052 if (!is_speculative && !has_try_catch) {
2053 // If we know that the method always throws with the particular parameters, set it as such.
2054 // This is better than using the dex instructions as we have more information about this
2055 // particular call. We don't mark speculative inlines (e.g. the ones from the inline cache) as
2056 // always throwing since they might not throw when executed.
2057 invoke->SetAlwaysThrows(/* always_throws= */ true);
2058 graph_->SetHasAlwaysThrowingInvokes(/* value= */ true);
2059 }
2060
2061 // Methods that contain infinite loops with try catches fall into this line too as we construct
2062 // an Exit block for them. This will mean that the stat `kNotInlinedAlwaysThrows` might not be
2063 // 100% correct but:
2064 // 1) This is a very small fraction of methods, and
2065 // 2) It is not easy to disambiguate between those.
2066 // Since we want to avoid inlining methods with infinite loops anyway, we return false for these
2067 // cases too.
2068 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedAlwaysThrows)
2069 << "Method " << resolved_method->PrettyMethod()
2070 << " could not be inlined because it always throws";
2071 return false;
2072 }
2073
2074 const bool too_many_registers =
2075 total_number_of_dex_registers_ > kMaximumNumberOfCumulatedDexRegisters;
2076 bool needs_bss_check = false;
2077 const bool can_encode_in_stack_map = CanEncodeInlinedMethodInStackMap(
2078 *outer_compilation_unit_.GetDexFile(), resolved_method, codegen_, &needs_bss_check);
2079 size_t number_of_instructions = 0;
2080 // Skip the entry block, it does not contain instructions that prevent inlining.
2081 for (HBasicBlock* block : callee_graph->GetReversePostOrderSkipEntryBlock()) {
2082 if (block->IsLoopHeader()) {
2083 if (block->GetLoopInformation()->IsIrreducible()) {
2084 // Don't inline methods with irreducible loops, they could prevent some
2085 // optimizations to run.
2086 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedIrreducibleLoopCallee)
2087 << "Method " << resolved_method->PrettyMethod()
2088 << " could not be inlined because it contains an irreducible loop";
2089 return false;
2090 }
2091 if (!block->GetLoopInformation()->HasExitEdge()) {
2092 // Don't inline methods with loops without exit, since they cause the
2093 // loop information to be computed incorrectly when updating after
2094 // inlining.
2095 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedLoopWithoutExit)
2096 << "Method " << resolved_method->PrettyMethod()
2097 << " could not be inlined because it contains a loop with no exit";
2098 return false;
2099 }
2100 }
2101
2102 for (HInstructionIterator instr_it(block->GetInstructions());
2103 !instr_it.Done();
2104 instr_it.Advance()) {
2105 if (++number_of_instructions > inlining_budget_) {
2106 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInstructionBudget)
2107 << "Method " << resolved_method->PrettyMethod()
2108 << " is not inlined because the outer method has reached"
2109 << " its instruction budget limit.";
2110 return false;
2111 }
2112 HInstruction* current = instr_it.Current();
2113 if (current->NeedsEnvironment()) {
2114 if (too_many_registers) {
2115 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedEnvironmentBudget)
2116 << "Method " << resolved_method->PrettyMethod()
2117 << " is not inlined because its caller has reached"
2118 << " its environment budget limit.";
2119 return false;
2120 }
2121
2122 if (!can_encode_in_stack_map) {
2123 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedStackMaps)
2124 << "Method " << resolved_method->PrettyMethod() << " could not be inlined because "
2125 << current->DebugName() << " needs an environment, is in a different dex file"
2126 << ", and cannot be encoded in the stack maps.";
2127 return false;
2128 }
2129 }
2130
2131 if (current->IsUnresolvedStaticFieldGet() ||
2132 current->IsUnresolvedInstanceFieldGet() ||
2133 current->IsUnresolvedStaticFieldSet() ||
2134 current->IsUnresolvedInstanceFieldSet() ||
2135 current->IsInvokeUnresolved()) {
2136 // Unresolved invokes / field accesses are expensive at runtime when decoding inlining info,
2137 // so don't inline methods that have them.
2138 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedUnresolvedEntrypoint)
2139 << "Method " << resolved_method->PrettyMethod()
2140 << " could not be inlined because it is using an unresolved"
2141 << " entrypoint";
2142 return false;
2143 }
2144
2145 // We currently don't have support for inlining across dex files if we are:
2146 // 1) In AoT,
2147 // 2) cross-dex inlining,
2148 // 3) the callee is a BCP DexFile,
2149 // 4) we are compiling multi image, and
2150 // 5) have an instruction that needs a bss entry, which will always be
2151 // 5)b) an instruction that needs an environment.
2152 // 1) - 4) are encoded in `needs_bss_check` (see CanEncodeInlinedMethodInStackMap).
2153 if (needs_bss_check && current->NeedsBss()) {
2154 DCHECK(current->NeedsEnvironment());
2155 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedBss)
2156 << "Method " << resolved_method->PrettyMethod()
2157 << " could not be inlined because it needs a BSS check";
2158 return false;
2159 }
2160
2161 if (outermost_graph_->IsCompilingBaseline() &&
2162 (current->IsInvokeVirtual() || current->IsInvokeInterface()) &&
2163 ProfilingInfoBuilder::IsInlineCacheUseful(current->AsInvoke(), codegen_)) {
2164 uint32_t maximum_inlining_depth_for_baseline =
2165 InlineCache::MaxDexPcEncodingDepth(
2166 outermost_graph_->GetArtMethod(),
2167 codegen_->GetCompilerOptions().GetInlineMaxCodeUnits());
2168 if (depth_ + 1 > maximum_inlining_depth_for_baseline) {
2169 LOG_FAIL_NO_STAT() << "Reached maximum depth for inlining in baseline compilation: "
2170 << depth_ << " for " << callee_graph->GetArtMethod()->PrettyMethod();
2171 outermost_graph_->SetUsefulOptimizing();
2172 return false;
2173 }
2174 }
2175 }
2176 }
2177
2178 *out_number_of_instructions = number_of_instructions;
2179 return true;
2180 }
2181
TryBuildAndInlineHelper(HInvoke * invoke_instruction,ArtMethod * resolved_method,ReferenceTypeInfo receiver_type,HInstruction ** return_replacement,bool is_speculative)2182 bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
2183 ArtMethod* resolved_method,
2184 ReferenceTypeInfo receiver_type,
2185 HInstruction** return_replacement,
2186 bool is_speculative) {
2187 DCHECK_IMPLIES(resolved_method->IsStatic(), !receiver_type.IsValid());
2188 DCHECK_IMPLIES(!resolved_method->IsStatic(), receiver_type.IsValid());
2189 const dex::CodeItem* code_item = resolved_method->GetCodeItem();
2190 const DexFile& callee_dex_file = *resolved_method->GetDexFile();
2191 uint32_t method_index = resolved_method->GetDexMethodIndex();
2192 CodeItemDebugInfoAccessor code_item_accessor(resolved_method->DexInstructionDebugInfo());
2193 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
2194 Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(),
2195 caller_compilation_unit_.GetDexCache(),
2196 graph_);
2197 Handle<mirror::ClassLoader> class_loader =
2198 NewHandleIfDifferent(resolved_method->GetDeclaringClass()->GetClassLoader(),
2199 caller_compilation_unit_.GetClassLoader(),
2200 graph_);
2201
2202 Handle<mirror::Class> compiling_class =
2203 graph_->GetHandleCache()->NewHandle(resolved_method->GetDeclaringClass());
2204 DexCompilationUnit dex_compilation_unit(
2205 class_loader,
2206 class_linker,
2207 callee_dex_file,
2208 code_item,
2209 resolved_method->GetDeclaringClass()->GetDexClassDefIndex(),
2210 method_index,
2211 resolved_method->GetAccessFlags(),
2212 /* verified_method= */ nullptr,
2213 dex_cache,
2214 compiling_class);
2215
2216 InvokeType invoke_type = invoke_instruction->GetInvokeType();
2217 if (invoke_type == kInterface) {
2218 // We have statically resolved the dispatch. To please the class linker
2219 // at runtime, we change this call as if it was a virtual call.
2220 invoke_type = kVirtual;
2221 }
2222
2223 bool caller_dead_reference_safe = graph_->IsDeadReferenceSafe();
2224 const dex::ClassDef& callee_class = resolved_method->GetClassDef();
2225 // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation()
2226 // is currently rarely true.
2227 bool callee_dead_reference_safe =
2228 annotations::HasDeadReferenceSafeAnnotation(callee_dex_file, callee_class)
2229 && !annotations::MethodContainsRSensitiveAccess(callee_dex_file, callee_class, method_index);
2230
2231 const int32_t caller_instruction_counter = graph_->GetCurrentInstructionId();
2232 HGraph* callee_graph = new (graph_->GetAllocator()) HGraph(
2233 graph_->GetAllocator(),
2234 graph_->GetArenaStack(),
2235 graph_->GetHandleCache()->GetHandles(),
2236 callee_dex_file,
2237 method_index,
2238 codegen_->GetCompilerOptions().GetInstructionSet(),
2239 invoke_type,
2240 callee_dead_reference_safe,
2241 graph_->IsDebuggable(),
2242 graph_->GetCompilationKind(),
2243 /* start_instruction_id= */ caller_instruction_counter);
2244 callee_graph->SetArtMethod(resolved_method);
2245
2246 ScopedProfilingInfoUse spiu(Runtime::Current()->GetJit(), resolved_method, Thread::Current());
2247 if (Runtime::Current()->GetJit() != nullptr) {
2248 callee_graph->SetProfilingInfo(spiu.GetProfilingInfo());
2249 }
2250
2251 // When they are needed, allocate `inline_stats_` on the Arena instead
2252 // of on the stack, as Clang might produce a stack frame too large
2253 // for this function, that would not fit the requirements of the
2254 // `-Wframe-larger-than` option.
2255 if (stats_ != nullptr) {
2256 // Reuse one object for all inline attempts from this caller to keep Arena memory usage low.
2257 if (inline_stats_ == nullptr) {
2258 void* storage = graph_->GetAllocator()->Alloc<OptimizingCompilerStats>(kArenaAllocMisc);
2259 inline_stats_ = new (storage) OptimizingCompilerStats;
2260 } else {
2261 inline_stats_->Reset();
2262 }
2263 }
2264 HGraphBuilder builder(callee_graph,
2265 code_item_accessor,
2266 &dex_compilation_unit,
2267 &outer_compilation_unit_,
2268 codegen_,
2269 inline_stats_);
2270
2271 if (builder.BuildGraph() != kAnalysisSuccess) {
2272 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCannotBuild)
2273 << "Method " << callee_dex_file.PrettyMethod(method_index)
2274 << " could not be built, so cannot be inlined";
2275 return false;
2276 }
2277
2278 SubstituteArguments(callee_graph, invoke_instruction, receiver_type, dex_compilation_unit);
2279
2280 const bool try_catch_inlining_allowed_for_recursive_inline =
2281 // It was allowed previously.
2282 try_catch_inlining_allowed_ &&
2283 // The current invoke is not a try block.
2284 !invoke_instruction->GetBlock()->IsTryBlock();
2285 RunOptimizations(callee_graph,
2286 invoke_instruction->GetEnvironment(),
2287 code_item,
2288 dex_compilation_unit,
2289 try_catch_inlining_allowed_for_recursive_inline);
2290
2291 size_t number_of_instructions = 0;
2292 if (!CanInlineBody(callee_graph, invoke_instruction, &number_of_instructions, is_speculative)) {
2293 return false;
2294 }
2295
2296 DCHECK_EQ(caller_instruction_counter, graph_->GetCurrentInstructionId())
2297 << "No instructions can be added to the outer graph while inner graph is being built";
2298
2299 // Inline the callee graph inside the caller graph.
2300 const int32_t callee_instruction_counter = callee_graph->GetCurrentInstructionId();
2301 graph_->SetCurrentInstructionId(callee_instruction_counter);
2302 *return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);
2303 // Update our budget for other inlining attempts in `caller_graph`.
2304 total_number_of_instructions_ += number_of_instructions;
2305 UpdateInliningBudget();
2306
2307 DCHECK_EQ(callee_instruction_counter, callee_graph->GetCurrentInstructionId())
2308 << "No instructions can be added to the inner graph during inlining into the outer graph";
2309
2310 if (stats_ != nullptr) {
2311 DCHECK(inline_stats_ != nullptr);
2312 inline_stats_->AddTo(stats_);
2313 }
2314
2315 if (caller_dead_reference_safe && !callee_dead_reference_safe) {
2316 // Caller was dead reference safe, but is not anymore, since we inlined dead
2317 // reference unsafe code. Prior transformations remain valid, since they did not
2318 // affect the inlined code.
2319 graph_->MarkDeadReferenceUnsafe();
2320 }
2321
2322 return true;
2323 }
2324
RunOptimizations(HGraph * callee_graph,HEnvironment * caller_environment,const dex::CodeItem * code_item,const DexCompilationUnit & dex_compilation_unit,bool try_catch_inlining_allowed_for_recursive_inline)2325 void HInliner::RunOptimizations(HGraph* callee_graph,
2326 HEnvironment* caller_environment,
2327 const dex::CodeItem* code_item,
2328 const DexCompilationUnit& dex_compilation_unit,
2329 bool try_catch_inlining_allowed_for_recursive_inline) {
2330 // Note: if the outermost_graph_ is being compiled OSR, we should not run any
2331 // optimization that could lead to a HDeoptimize. The following optimizations do not.
2332 HDeadCodeElimination dce(callee_graph, inline_stats_, "dead_code_elimination$inliner");
2333 HConstantFolding fold(callee_graph, inline_stats_, "constant_folding$inliner");
2334 InstructionSimplifier simplify(callee_graph, codegen_, inline_stats_);
2335
2336 HOptimization* optimizations[] = {
2337 &fold,
2338 &simplify,
2339 &dce,
2340 };
2341
2342 for (size_t i = 0; i < arraysize(optimizations); ++i) {
2343 HOptimization* optimization = optimizations[i];
2344 optimization->Run();
2345 }
2346
2347 // Bail early for pathological cases on the environment (for example recursive calls,
2348 // or too large environment).
2349 if (total_number_of_dex_registers_ > kMaximumNumberOfCumulatedDexRegisters) {
2350 LOG_NOTE() << "Calls in " << callee_graph->GetArtMethod()->PrettyMethod()
2351 << " will not be inlined because the outer method has reached"
2352 << " its environment budget limit.";
2353 return;
2354 }
2355
2356 // Bail early if we know we already are over the limit.
2357 size_t number_of_instructions = CountNumberOfInstructions(callee_graph);
2358 if (number_of_instructions > inlining_budget_) {
2359 LOG_NOTE() << "Calls in " << callee_graph->GetArtMethod()->PrettyMethod()
2360 << " will not be inlined because the outer method has reached"
2361 << " its instruction budget limit. " << number_of_instructions;
2362 return;
2363 }
2364
2365 CodeItemDataAccessor accessor(callee_graph->GetDexFile(), code_item);
2366 HInliner inliner(callee_graph,
2367 outermost_graph_,
2368 codegen_,
2369 outer_compilation_unit_,
2370 dex_compilation_unit,
2371 inline_stats_,
2372 total_number_of_dex_registers_ + accessor.RegistersSize(),
2373 total_number_of_instructions_ + number_of_instructions,
2374 this,
2375 caller_environment,
2376 depth_ + 1,
2377 try_catch_inlining_allowed_for_recursive_inline);
2378 inliner.Run();
2379 }
2380
IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,bool declared_is_exact,bool declared_can_be_null,HInstruction * actual_obj)2381 static bool IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,
2382 bool declared_is_exact,
2383 bool declared_can_be_null,
2384 HInstruction* actual_obj)
2385 REQUIRES_SHARED(Locks::mutator_lock_) {
2386 if (declared_can_be_null && !actual_obj->CanBeNull()) {
2387 return true;
2388 }
2389
2390 ReferenceTypeInfo actual_rti = actual_obj->GetReferenceTypeInfo();
2391 if (!actual_rti.IsValid()) {
2392 return false;
2393 }
2394
2395 ObjPtr<mirror::Class> actual_class = actual_rti.GetTypeHandle().Get();
2396 return (actual_rti.IsExact() && !declared_is_exact) ||
2397 (declared_class != actual_class && declared_class->IsAssignableFrom(actual_class));
2398 }
2399
IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,bool declared_can_be_null,HInstruction * actual_obj)2400 static bool IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,
2401 bool declared_can_be_null,
2402 HInstruction* actual_obj)
2403 REQUIRES_SHARED(Locks::mutator_lock_) {
2404 bool admissible = ReferenceTypePropagation::IsAdmissible(declared_class);
2405 return IsReferenceTypeRefinement(
2406 admissible ? declared_class : GetClassRoot<mirror::Class>(),
2407 /*declared_is_exact=*/ admissible && declared_class->CannotBeAssignedFromOtherTypes(),
2408 declared_can_be_null,
2409 actual_obj);
2410 }
2411
ArgumentTypesMoreSpecific(HInvoke * invoke_instruction,ArtMethod * resolved_method)2412 bool HInliner::ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod* resolved_method) {
2413 // If this is an instance call, test whether the type of the `this` argument
2414 // is more specific than the class which declares the method.
2415 if (!resolved_method->IsStatic()) {
2416 if (IsReferenceTypeRefinement(resolved_method->GetDeclaringClass(),
2417 /*declared_can_be_null=*/ false,
2418 invoke_instruction->InputAt(0u))) {
2419 return true;
2420 }
2421 }
2422
2423 // Iterate over the list of parameter types and test whether any of the
2424 // actual inputs has a more specific reference type than the type declared in
2425 // the signature.
2426 const dex::TypeList* param_list = resolved_method->GetParameterTypeList();
2427 for (size_t param_idx = 0,
2428 input_idx = resolved_method->IsStatic() ? 0 : 1,
2429 e = (param_list == nullptr ? 0 : param_list->Size());
2430 param_idx < e;
2431 ++param_idx, ++input_idx) {
2432 HInstruction* input = invoke_instruction->InputAt(input_idx);
2433 if (input->GetType() == DataType::Type::kReference) {
2434 ObjPtr<mirror::Class> param_cls = resolved_method->LookupResolvedClassFromTypeIndex(
2435 param_list->GetTypeItem(param_idx).type_idx_);
2436 if (IsReferenceTypeRefinement(param_cls, /*declared_can_be_null=*/ true, input)) {
2437 return true;
2438 }
2439 }
2440 }
2441
2442 return false;
2443 }
2444
ReturnTypeMoreSpecific(HInstruction * return_replacement,HInvoke * invoke_instruction)2445 bool HInliner::ReturnTypeMoreSpecific(HInstruction* return_replacement,
2446 HInvoke* invoke_instruction) {
2447 // Check the integrity of reference types and run another type propagation if needed.
2448 if (return_replacement != nullptr) {
2449 if (return_replacement->GetType() == DataType::Type::kReference) {
2450 // Test if the return type is a refinement of the declared return type.
2451 ReferenceTypeInfo invoke_rti = invoke_instruction->GetReferenceTypeInfo();
2452 if (IsReferenceTypeRefinement(invoke_rti.GetTypeHandle().Get(),
2453 invoke_rti.IsExact(),
2454 invoke_instruction->CanBeNull(),
2455 return_replacement)) {
2456 return true;
2457 } else if (return_replacement->IsInstanceFieldGet()) {
2458 HInstanceFieldGet* field_get = return_replacement->AsInstanceFieldGet();
2459 ArtField* cls_field = WellKnownClasses::java_lang_Object_shadowKlass;
2460 if (field_get->GetFieldInfo().GetField() == cls_field) {
2461 return true;
2462 }
2463 }
2464 } else if (return_replacement->IsInstanceOf()) {
2465 // Inlining InstanceOf into an If may put a tighter bound on reference types.
2466 return true;
2467 }
2468 }
2469
2470 return false;
2471 }
2472
FixUpReturnReferenceType(ArtMethod * resolved_method,HInstruction * return_replacement)2473 void HInliner::FixUpReturnReferenceType(ArtMethod* resolved_method,
2474 HInstruction* return_replacement) {
2475 if (return_replacement != nullptr) {
2476 if (return_replacement->GetType() == DataType::Type::kReference) {
2477 if (!return_replacement->GetReferenceTypeInfo().IsValid()) {
2478 // Make sure that we have a valid type for the return. We may get an invalid one when
2479 // we inline invokes with multiple branches and create a Phi for the result.
2480 // TODO: we could be more precise by merging the phi inputs but that requires
2481 // some functionality from the reference type propagation.
2482 DCHECK(return_replacement->IsPhi());
2483 ObjPtr<mirror::Class> cls = resolved_method->LookupResolvedReturnType();
2484 ReferenceTypeInfo rti = ReferenceTypePropagation::IsAdmissible(cls)
2485 ? ReferenceTypeInfo::Create(graph_->GetHandleCache()->NewHandle(cls))
2486 : graph_->GetInexactObjectRti();
2487 return_replacement->SetReferenceTypeInfo(rti);
2488 }
2489 }
2490 }
2491 }
2492
2493 } // namespace art
2494