blob: 32f6972c8450848e60e482107485867a08b3eb30 [file] [log] [blame]
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "inliner.h"
18
19#include "builder.h"
20#include "class_linker.h"
21#include "constant_folding.h"
22#include "dead_code_elimination.h"
23#include "driver/compiler_driver-inl.h"
24#include "driver/dex_compilation_unit.h"
25#include "instruction_simplifier.h"
26#include "mirror/art_method-inl.h"
27#include "mirror/class_loader.h"
28#include "mirror/dex_cache.h"
29#include "nodes.h"
Nicolas Geoffray259136f2014-12-17 23:21:58 +000030#include "register_allocator.h"
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000031#include "ssa_phi_elimination.h"
32#include "scoped_thread_state_change.h"
33#include "thread.h"
34
35namespace art {
36
37static constexpr int kMaxInlineCodeUnits = 100;
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +000038static constexpr int kDepthLimit = 5;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000039
40void HInliner::Run() {
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +000041 const GrowableArray<HBasicBlock*>& blocks = graph_->GetReversePostOrder();
42 for (size_t i = 0; i < blocks.Size(); ++i) {
43 HBasicBlock* block = blocks.Get(i);
44 for (HInstruction* instruction = block->GetFirstInstruction(); instruction != nullptr;) {
45 HInstruction* next = instruction->GetNext();
46 HInvokeStaticOrDirect* call = instruction->AsInvokeStaticOrDirect();
47 if (call != nullptr) {
48 if (!TryInline(call, call->GetDexMethodIndex(), call->GetInvokeType())) {
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000049 if (kIsDebugBuild) {
50 std::string callee_name =
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +000051 PrettyMethod(call->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000052 bool should_inline = callee_name.find("$inline$") != std::string::npos;
53 CHECK(!should_inline) << "Could not inline " << callee_name;
54 }
55 }
56 }
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +000057 instruction = next;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000058 }
59 }
60}
61
62bool HInliner::TryInline(HInvoke* invoke_instruction,
63 uint32_t method_index,
64 InvokeType invoke_type) const {
65 ScopedObjectAccess soa(Thread::Current());
66 const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
67 VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, outer_dex_file);
68
69 StackHandleScope<3> hs(soa.Self());
70 Handle<mirror::DexCache> dex_cache(
71 hs.NewHandle(outer_compilation_unit_.GetClassLinker()->FindDexCache(outer_dex_file)));
72 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
73 soa.Decode<mirror::ClassLoader*>(outer_compilation_unit_.GetClassLoader())));
74 Handle<mirror::ArtMethod> resolved_method(hs.NewHandle(
75 compiler_driver_->ResolveMethod(
76 soa, dex_cache, class_loader, &outer_compilation_unit_, method_index, invoke_type)));
77
78 if (resolved_method.Get() == nullptr) {
79 VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, outer_dex_file);
80 return false;
81 }
82
83 if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) {
84 VLOG(compiler) << "Did not inline "
85 << PrettyMethod(method_index, outer_dex_file)
86 << " because it is in a different dex file";
87 return false;
88 }
89
90 const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
91
92 if (code_item == nullptr) {
93 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
94 << " is not inlined because it is native";
95 return false;
96 }
97
98 if (code_item->insns_size_in_code_units_ > kMaxInlineCodeUnits) {
99 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
100 << " is too big to inline";
101 return false;
102 }
103
104 if (code_item->tries_size_ != 0) {
105 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
106 << " is not inlined because of try block";
107 return false;
108 }
109
110 if (!resolved_method->GetDeclaringClass()->IsVerified()) {
111 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
112 << " is not inlined because its class could not be verified";
113 return false;
114 }
115
116 DexCompilationUnit dex_compilation_unit(
117 nullptr,
118 outer_compilation_unit_.GetClassLoader(),
119 outer_compilation_unit_.GetClassLinker(),
120 outer_dex_file,
121 code_item,
122 resolved_method->GetDeclaringClass()->GetDexClassDefIndex(),
123 method_index,
124 resolved_method->GetAccessFlags(),
125 nullptr);
126
David Brazdil5e8b1372015-01-23 14:39:08 +0000127 HGraph* callee_graph =
128 new (graph_->GetArena()) HGraph(graph_->GetArena(), graph_->GetCurrentInstructionId());
129
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000130 OptimizingCompilerStats inline_stats;
David Brazdil5e8b1372015-01-23 14:39:08 +0000131 HGraphBuilder builder(callee_graph,
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000132 &dex_compilation_unit,
133 &outer_compilation_unit_,
134 &outer_dex_file,
135 compiler_driver_,
136 &inline_stats);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000137
David Brazdil5e8b1372015-01-23 14:39:08 +0000138 if (!builder.BuildGraph(*code_item)) {
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000139 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
140 << " could not be built, so cannot be inlined";
141 return false;
142 }
143
Nicolas Geoffray259136f2014-12-17 23:21:58 +0000144 if (!RegisterAllocator::CanAllocateRegistersFor(*callee_graph,
145 compiler_driver_->GetInstructionSet())) {
146 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
147 << " cannot be inlined because of the register allocator";
148 return false;
149 }
150
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000151 if (!callee_graph->TryBuildingSsa()) {
152 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
153 << " could not be transformed to SSA";
154 return false;
155 }
156
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +0000157 // Run simple optimizations on the graph.
158 SsaRedundantPhiElimination redundant_phi(callee_graph);
159 SsaDeadPhiElimination dead_phi(callee_graph);
160 HDeadCodeElimination dce(callee_graph);
161 HConstantFolding fold(callee_graph);
162 InstructionSimplifier simplify(callee_graph);
163
164 HOptimization* optimizations[] = {
165 &redundant_phi,
166 &dead_phi,
167 &dce,
168 &fold,
169 &simplify,
170 };
171
172 for (size_t i = 0; i < arraysize(optimizations); ++i) {
173 HOptimization* optimization = optimizations[i];
174 optimization->Run();
175 }
176
177 if (depth_ + 1 < kDepthLimit) {
178 HInliner inliner(
179 callee_graph, outer_compilation_unit_, compiler_driver_, outer_stats_, depth_ + 1);
180 inliner.Run();
181 }
182
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000183 HReversePostOrderIterator it(*callee_graph);
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +0000184 it.Advance(); // Past the entry block, it does not contain instructions that prevent inlining.
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000185 for (; !it.Done(); it.Advance()) {
186 HBasicBlock* block = it.Current();
187 if (block->IsLoopHeader()) {
188 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
189 << " could not be inlined because it contains a loop";
190 return false;
191 }
192
193 for (HInstructionIterator instr_it(block->GetInstructions());
194 !instr_it.Done();
195 instr_it.Advance()) {
196 HInstruction* current = instr_it.Current();
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000197 if (current->IsSuspendCheck()) {
198 continue;
199 }
200
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000201 if (current->CanThrow()) {
202 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
203 << " could not be inlined because " << current->DebugName()
204 << " can throw";
205 return false;
206 }
207
208 if (current->NeedsEnvironment()) {
209 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
210 << " could not be inlined because " << current->DebugName()
211 << " needs an environment";
212 return false;
213 }
214 }
215 }
216
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000217 callee_graph->InlineInto(graph_, invoke_instruction);
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000218
219 // Now that we have inlined the callee, we need to update the next
220 // instruction id of the caller, so that new instructions added
221 // after optimizations get a unique id.
222 graph_->SetCurrentInstructionId(callee_graph->GetNextInstructionId());
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000223 VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, outer_dex_file);
224 outer_stats_->RecordStat(kInlinedInvoke);
225 return true;
226}
227
228} // namespace art