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