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