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
}
}
-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();
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
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();
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;
}
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);
HOptimization* optimizations[] = {
&intrinsics,
- &dce,
- &fold,
&type_propagation,
&simplify,
+ &dce,
+ &fold,
};
for (size_t i = 0; i < arraysize(optimizations); ++i) {
optimization->Run();
}
+ size_t number_of_instructions_budget = kMaximumNumberOfHInstructions;
if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) {
HInliner inliner(callee_graph,
outer_compilation_unit_,
stats_,
depth_ + 1);
inliner.Run();
+ number_of_instructions_budget += inliner.number_of_inlined_instructions_;
}
// TODO: We should abort only if all predecessors throw. However,
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;
}
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()) {
// 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;
}
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);
class HParameterValue : public HExpression<0> {
public:
HParameterValue(uint8_t index, Primitive::Type parameter_type, bool is_this = false)
- : HExpression(parameter_type, SideEffects::None()), index_(index), is_this_(is_this) {}
+ : HExpression(parameter_type, SideEffects::None()),
+ index_(index),
+ is_this_(is_this),
+ can_be_null_(!is_this) {}
uint8_t GetIndex() const { return index_; }
- bool CanBeNull() const OVERRIDE { return !is_this_; }
+ bool CanBeNull() const OVERRIDE { return can_be_null_; }
+ void SetCanBeNull(bool can_be_null) { can_be_null_ = can_be_null; }
bool IsThis() const { return is_this_; }
// Whether or not the parameter value corresponds to 'this' argument.
const bool is_this_;
+ bool can_be_null_;
+
DISALLOW_COPY_AND_ASSIGN(HParameterValue);
};
// TODO: Can we deopt or debug when we resolve a string?
bool NeedsEnvironment() const OVERRIDE { return false; }
bool NeedsDexCache() const OVERRIDE { return true; }
+ bool CanBeNull() const OVERRIDE { return false; }
static SideEffects SideEffectsForArchRuntimeCalls() {
return SideEffects::CanTriggerGC();
/// CHECK-DAG: Return [<<Result>>]
/// CHECK-START: int Main.InlineAdd() inliner (after)
- /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
- /// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
- /// CHECK-DAG: <<Add:i\d+>> Add [<<Const3>>,<<Const5>>]
- /// CHECK-DAG: Return [<<Add>>]
+ /// CHECK-DAG: <<Const8:i\d+>> IntConstant 8
+ /// CHECK-DAG: Return [<<Const8>>]
public static int InlineAdd() {
return returnAdd(3, 5);
/// CHECK-DAG: Return [<<Phi>>]
/// CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (after)
- /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
- /// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
- /// CHECK-DAG: <<Add:i\d+>> Add [<<Const1>>,<<Const3>>]
- /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const5>>,<<Const3>>]
- /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Sub>>]
+ /// CHECK-DAG: <<Const4:i\d+>> IntConstant 4
+ /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const4>>,<<Const2>>]
/// CHECK-DAG: Return [<<Phi>>]
public static int InlineWithControlFlow(boolean cond) {