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