summaryrefslogtreecommitdiff
path: root/compiler/optimizing/inliner.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/inliner.cc')
-rw-r--r--compiler/optimizing/inliner.cc62
1 files changed, 41 insertions, 21 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 202f3f074d..ff90f32754 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -40,6 +40,8 @@
namespace art {
+static constexpr size_t kMaximumNumberOfHInstructions = 12;
+
void HInliner::Run() {
if (graph_->IsDebuggable()) {
// For simplicity, we currently never inline when the graph is debuggable. This avoids
@@ -169,7 +171,7 @@ static uint32_t FindMethodIndexIn(ArtMethod* method,
}
}
-bool HInliner::TryInline(HInvoke* invoke_instruction) const {
+bool HInliner::TryInline(HInvoke* invoke_instruction) {
uint32_t method_index = invoke_instruction->GetDexMethodIndex();
ScopedObjectAccess soa(Thread::Current());
const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
@@ -244,12 +246,6 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) const {
return false;
}
- if (resolved_method->ShouldNotInline()) {
- VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
- << " was already flagged as non inlineable";
- return false;
- }
-
if (invoke_instruction->IsInvokeStaticOrDirect() &&
invoke_instruction->AsInvokeStaticOrDirect()->IsStaticWithImplicitClinitCheck()) {
// Case of a static method that cannot be inlined because it implicitly
@@ -271,7 +267,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) const {
bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
HInvoke* invoke_instruction,
- bool same_dex_file) const {
+ bool same_dex_file) {
ScopedObjectAccess soa(Thread::Current());
const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
const DexFile& callee_dex_file = *resolved_method->GetDexFile();
@@ -335,9 +331,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
if (!builder.BuildGraph(*code_item)) {
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be built, so cannot be inlined";
- // There could be multiple reasons why the graph could not be built, including
- // unaccessible methods/fields due to using a different dex cache. We do not mark
- // the method as non-inlineable so that other callers can still try to inline it.
return false;
}
@@ -345,17 +338,41 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
compiler_driver_->GetInstructionSet())) {
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " cannot be inlined because of the register allocator";
- resolved_method->SetShouldNotInline();
return false;
}
if (!callee_graph->TryBuildingSsa()) {
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be transformed to SSA";
- resolved_method->SetShouldNotInline();
return false;
}
+ size_t parameter_index = 0;
+ for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions());
+ !instructions.Done();
+ instructions.Advance()) {
+ HInstruction* current = instructions.Current();
+ if (current->IsParameterValue()) {
+ HInstruction* argument = invoke_instruction->InputAt(parameter_index++);
+ if (argument->IsNullConstant()) {
+ current->ReplaceWith(callee_graph->GetNullConstant());
+ } else if (argument->IsIntConstant()) {
+ current->ReplaceWith(callee_graph->GetIntConstant(argument->AsIntConstant()->GetValue()));
+ } else if (argument->IsLongConstant()) {
+ current->ReplaceWith(callee_graph->GetLongConstant(argument->AsLongConstant()->GetValue()));
+ } else if (argument->IsFloatConstant()) {
+ current->ReplaceWith(
+ callee_graph->GetFloatConstant(argument->AsFloatConstant()->GetValue()));
+ } else if (argument->IsDoubleConstant()) {
+ current->ReplaceWith(
+ callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue()));
+ } else if (argument->GetType() == Primitive::kPrimNot) {
+ current->SetReferenceTypeInfo(argument->GetReferenceTypeInfo());
+ current->AsParameterValue()->SetCanBeNull(argument->CanBeNull());
+ }
+ }
+ }
+
// Run simple optimizations on the graph.
HDeadCodeElimination dce(callee_graph, stats_);
HConstantFolding fold(callee_graph);
@@ -365,10 +382,10 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
HOptimization* optimizations[] = {
&intrinsics,
- &dce,
- &fold,
&type_propagation,
&simplify,
+ &dce,
+ &fold,
};
for (size_t i = 0; i < arraysize(optimizations); ++i) {
@@ -376,6 +393,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
optimization->Run();
}
+ size_t number_of_instructions_budget = kMaximumNumberOfHInstructions;
if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) {
HInliner inliner(callee_graph,
outer_compilation_unit_,
@@ -385,6 +403,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
stats_,
depth_ + 1);
inliner.Run();
+ number_of_instructions_budget += inliner.number_of_inlined_instructions_;
}
// TODO: We should abort only if all predecessors throw. However,
@@ -394,7 +413,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
if (exit_block == nullptr) {
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be inlined because it has an infinite loop";
- resolved_method->SetShouldNotInline();
return false;
}
@@ -408,24 +426,28 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
if (has_throw_predecessor) {
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be inlined because one branch always throws";
- resolved_method->SetShouldNotInline();
return false;
}
HReversePostOrderIterator it(*callee_graph);
it.Advance(); // Past the entry block, it does not contain instructions that prevent inlining.
+ size_t number_of_instructions = 0;
for (; !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
if (block->IsLoopHeader()) {
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be inlined because it contains a loop";
- resolved_method->SetShouldNotInline();
return false;
}
for (HInstructionIterator instr_it(block->GetInstructions());
!instr_it.Done();
instr_it.Advance()) {
+ if (number_of_instructions++ == number_of_instructions_budget) {
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it is too big.";
+ return false;
+ }
HInstruction* current = instr_it.Current();
if (current->IsInvokeInterface()) {
@@ -433,7 +455,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
// resolution conflict is currently too high.
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be inlined because it has an interface call.";
- resolved_method->SetShouldNotInline();
return false;
}
@@ -448,12 +469,11 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be inlined because " << current->DebugName()
<< " it is in a different dex file and requires access to the dex cache";
- // Do not flag the method as not-inlineable. A caller within the same
- // dex file could still successfully inline it.
return false;
}
}
}
+ number_of_inlined_instructions_ += number_of_instructions;
HInstruction* return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);