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