blob: 1de5b7812185fca0fa86a12e5cadcb3329114bd3 [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"
30#include "ssa_phi_elimination.h"
31#include "scoped_thread_state_change.h"
32#include "thread.h"
33
34namespace art {
35
36static constexpr int kMaxInlineCodeUnits = 100;
37static constexpr int kMaxInlineNumberOfBlocks = 3;
38
39void HInliner::Run() {
40 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
41 for (HInstructionIterator instr_it(it.Current()->GetInstructions());
42 !instr_it.Done();
43 instr_it.Advance()) {
44 HInvokeStaticOrDirect* current = instr_it.Current()->AsInvokeStaticOrDirect();
45 if (current != nullptr) {
46 if (!TryInline(current, current->GetIndexInDexCache(), current->GetInvokeType())) {
47 if (kIsDebugBuild) {
48 std::string callee_name =
49 PrettyMethod(current->GetIndexInDexCache(), *outer_compilation_unit_.GetDexFile());
50 bool should_inline = callee_name.find("$inline$") != std::string::npos;
51 CHECK(!should_inline) << "Could not inline " << callee_name;
52 }
53 }
54 }
55 }
56 }
57}
58
59bool HInliner::TryInline(HInvoke* invoke_instruction,
60 uint32_t method_index,
61 InvokeType invoke_type) const {
62 ScopedObjectAccess soa(Thread::Current());
63 const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
64 VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, outer_dex_file);
65
66 StackHandleScope<3> hs(soa.Self());
67 Handle<mirror::DexCache> dex_cache(
68 hs.NewHandle(outer_compilation_unit_.GetClassLinker()->FindDexCache(outer_dex_file)));
69 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
70 soa.Decode<mirror::ClassLoader*>(outer_compilation_unit_.GetClassLoader())));
71 Handle<mirror::ArtMethod> resolved_method(hs.NewHandle(
72 compiler_driver_->ResolveMethod(
73 soa, dex_cache, class_loader, &outer_compilation_unit_, method_index, invoke_type)));
74
75 if (resolved_method.Get() == nullptr) {
76 VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, outer_dex_file);
77 return false;
78 }
79
80 if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) {
81 VLOG(compiler) << "Did not inline "
82 << PrettyMethod(method_index, outer_dex_file)
83 << " because it is in a different dex file";
84 return false;
85 }
86
87 const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
88
89 if (code_item == nullptr) {
90 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
91 << " is not inlined because it is native";
92 return false;
93 }
94
95 if (code_item->insns_size_in_code_units_ > kMaxInlineCodeUnits) {
96 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
97 << " is too big to inline";
98 return false;
99 }
100
101 if (code_item->tries_size_ != 0) {
102 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
103 << " is not inlined because of try block";
104 return false;
105 }
106
107 if (!resolved_method->GetDeclaringClass()->IsVerified()) {
108 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
109 << " is not inlined because its class could not be verified";
110 return false;
111 }
112
113 DexCompilationUnit dex_compilation_unit(
114 nullptr,
115 outer_compilation_unit_.GetClassLoader(),
116 outer_compilation_unit_.GetClassLinker(),
117 outer_dex_file,
118 code_item,
119 resolved_method->GetDeclaringClass()->GetDexClassDefIndex(),
120 method_index,
121 resolved_method->GetAccessFlags(),
122 nullptr);
123
124 OptimizingCompilerStats inline_stats;
125 HGraphBuilder builder(graph_->GetArena(),
126 &dex_compilation_unit,
127 &outer_compilation_unit_,
128 &outer_dex_file,
129 compiler_driver_,
130 &inline_stats);
131 HGraph* callee_graph = builder.BuildGraph(*code_item, graph_->GetCurrentInstructionId());
132
133 if (callee_graph == nullptr) {
134 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
135 << " could not be built, so cannot be inlined";
136 return false;
137 }
138
139 if (callee_graph->GetBlocks().Size() > kMaxInlineNumberOfBlocks) {
140 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
141 << " has too many blocks to be inlined: "
142 << callee_graph->GetBlocks().Size();
143 return false;
144 }
145
146 if (!callee_graph->TryBuildingSsa()) {
147 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
148 << " could not be transformed to SSA";
149 return false;
150 }
151
152 HReversePostOrderIterator it(*callee_graph);
153 it.Advance(); // Past the entry block to avoid seeing the suspend check.
154 for (; !it.Done(); it.Advance()) {
155 HBasicBlock* block = it.Current();
156 if (block->IsLoopHeader()) {
157 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
158 << " could not be inlined because it contains a loop";
159 return false;
160 }
161
162 for (HInstructionIterator instr_it(block->GetInstructions());
163 !instr_it.Done();
164 instr_it.Advance()) {
165 HInstruction* current = instr_it.Current();
166 if (current->CanThrow()) {
167 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
168 << " could not be inlined because " << current->DebugName()
169 << " can throw";
170 return false;
171 }
172
173 if (current->NeedsEnvironment()) {
174 VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
175 << " could not be inlined because " << current->DebugName()
176 << " needs an environment";
177 return false;
178 }
179 }
180 }
181
182 // Run simple optimizations on the graph.
183 SsaRedundantPhiElimination redundant_phi(callee_graph);
184 SsaDeadPhiElimination dead_phi(callee_graph);
185 HDeadCodeElimination dce(callee_graph);
186 HConstantFolding fold(callee_graph);
187 InstructionSimplifier simplify(callee_graph);
188
189 HOptimization* optimizations[] = {
190 &redundant_phi,
191 &dead_phi,
192 &dce,
193 &fold,
194 &simplify,
195 };
196
197 for (size_t i = 0; i < arraysize(optimizations); ++i) {
198 HOptimization* optimization = optimizations[i];
199 optimization->Run();
200 }
201
202 callee_graph->InlineInto(graph_, invoke_instruction);
203 VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, outer_dex_file);
204 outer_stats_->RecordStat(kInlinedInvoke);
205 return true;
206}
207
208} // namespace art