diff options
Diffstat (limited to 'compiler/optimizing/inliner.cc')
| -rw-r--r-- | compiler/optimizing/inliner.cc | 62 |
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); |