diff options
author | 2015-05-18 22:31:29 +0100 | |
---|---|---|
committer | 2015-05-29 14:15:04 +0100 | |
commit | d23eeef3492b53102eb8093524cf37e2b4c296db (patch) | |
tree | 57d3e9ab2853d5b8092568bb3d29bc850c113315 /compiler/optimizing/inliner.cc | |
parent | a15c78d3cc28f514a482ffd792a767e97fe53c95 (diff) |
Support for inlining methods that call/throw.
Mostly fixes here and there to make it working.
Change-Id: I1b535e895105d78b65634636d675b818551f783e
Diffstat (limited to 'compiler/optimizing/inliner.cc')
-rw-r--r-- | compiler/optimizing/inliner.cc | 67 |
1 files changed, 46 insertions, 21 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 997f980f45..15f3deb174 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -36,8 +36,8 @@ namespace art { -static constexpr int kMaxInlineCodeUnits = 100; -static constexpr int kDepthLimit = 5; +static constexpr int kMaxInlineCodeUnits = 18; +static constexpr int kDepthLimit = 3; void HInliner::Run() { if (graph_->IsDebuggable()) { @@ -46,8 +46,15 @@ void HInliner::Run() { return; } const GrowableArray<HBasicBlock*>& blocks = graph_->GetReversePostOrder(); + HBasicBlock* next_block = blocks.Get(0); for (size_t i = 0; i < blocks.Size(); ++i) { - HBasicBlock* block = blocks.Get(i); + // Because we are changing the graph when inlining, we need to remember the next block. + // This avoids doing the inlining work again on the inlined blocks. + if (blocks.Get(i) != next_block) { + continue; + } + HBasicBlock* block = next_block; + next_block = (i == blocks.Size() - 1) ? nullptr : blocks.Get(i + 1); for (HInstruction* instruction = block->GetFirstInstruction(); instruction != nullptr;) { HInstruction* next = instruction->GetNext(); HInvokeStaticOrDirect* call = instruction->AsInvokeStaticOrDirect(); @@ -90,10 +97,10 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, return false; } - bool can_use_dex_cache = true; + bool same_dex_file = true; const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile(); if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) { - can_use_dex_cache = false; + same_dex_file = false; } const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); @@ -140,7 +147,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, return false; } - if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index, can_use_dex_cache)) { + if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index, same_dex_file)) { return false; } @@ -152,7 +159,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, HInvoke* invoke_instruction, uint32_t method_index, - bool can_use_dex_cache) const { + bool same_dex_file) const { ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); @@ -254,6 +261,31 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, inliner.Run(); } + // TODO: We should abort only if all predecessors throw. However, + // HGraph::InlineInto currently does not handle an exit block with + // a throw predecessor. + HBasicBlock* exit_block = callee_graph->GetExitBlock(); + if (exit_block == nullptr) { + VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) + << " could not be inlined because it has an infinite loop"; + resolved_method->SetShouldNotInline(); + return false; + } + + bool has_throw_predecessor = false; + for (size_t i = 0, e = exit_block->GetPredecessors().Size(); i < e; ++i) { + if (exit_block->GetPredecessors().Get(i)->GetLastInstruction()->IsThrow()) { + has_throw_predecessor = true; + break; + } + } + if (has_throw_predecessor) { + VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_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. for (; !it.Done(); it.Advance()) { @@ -269,27 +301,24 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, !instr_it.Done(); instr_it.Advance()) { HInstruction* current = instr_it.Current(); - if (current->IsSuspendCheck()) { - continue; - } - if (current->CanThrow()) { + if (current->IsInvokeInterface()) { + // Disable inlining of interface calls. The cost in case of entering the + // resolution conflict is currently too high. VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) - << " could not be inlined because " << current->DebugName() - << " can throw"; + << " could not be inlined because it has an interface call."; resolved_method->SetShouldNotInline(); return false; } - if (current->NeedsEnvironment()) { + if (!same_dex_file && current->NeedsEnvironment()) { VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) << " could not be inlined because " << current->DebugName() - << " needs an environment"; - resolved_method->SetShouldNotInline(); + << " needs an environment and is in a different dex file"; return false; } - if (!can_use_dex_cache && current->NeedsDexCache()) { + if (!same_dex_file && current->NeedsDexCache()) { VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) << " could not be inlined because " << current->DebugName() << " it is in a different dex file and requires access to the dex cache"; @@ -302,10 +331,6 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, callee_graph->InlineInto(graph_, invoke_instruction); - if (callee_graph->HasBoundsChecks()) { - graph_->SetHasBoundsChecks(true); - } - return true; } |