Chromium Code Reviews| Index: runtime/vm/flow_graph_inliner.cc |
| diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc |
| index 76893c0b6092bf4f30189e03c9951c00cb131230..6b55e141331e8d3d172782129cd0b0f7268eb5ad 100644 |
| --- a/runtime/vm/flow_graph_inliner.cc |
| +++ b/runtime/vm/flow_graph_inliner.cc |
| @@ -26,18 +26,20 @@ class CallSiteInliner : public FlowGraphVisitor { |
| next_ssa_temp_index_(flow_graph->max_virtual_register_number()), |
| inlined_(false) { } |
| - void TryInlining(const Function& function, |
| + bool TryInlining(const Function& function, |
| GrowableArray<Value*>* arguments, |
| - StaticCallInstr* call) { |
| - // TODO(zerny): Generalize to all calls. |
| + Definition* call) { |
| + if (FLAG_trace_inlining) { |
| + OS::Print("--- %s\n", function.ToFullyQualifiedCString()); |
| + } |
| - // Abort if the callee has optional parameters. |
| + // Abort if the callee has named parameters. |
| if (function.HasOptionalParameters()) { |
| if (FLAG_trace_inlining) { |
| OS::Print("Inline aborted %s\nReason: optional parameters\n", |
| function.ToFullyQualifiedCString()); |
| } |
| - return; |
| + return false; |
| } |
| // Assuming no optional parameters the actual/formal count should match. |
| @@ -55,11 +57,12 @@ class CallSiteInliner : public FlowGraphVisitor { |
| // Parse the callee function. |
| ParsedFunction parsed_function(function); |
| Parser::ParseFunction(&parsed_function); |
| + parsed_function.AllocateVariables(); |
| FlowGraphBuilder builder(parsed_function); |
| // Build the callee graph. |
| FlowGraph* callee_graph = |
| - builder.BuildGraphForInlining(FlowGraphBuilder::kValueContext); |
| + builder.BuildGraph(FlowGraphBuilder::kValueContext); |
| // Abort if the callee graph contains control flow. |
| if (callee_graph->preorder().length() != 2) { |
| @@ -69,7 +72,7 @@ class CallSiteInliner : public FlowGraphVisitor { |
| OS::Print("Inline aborted %s\nReason: control flow\n", |
| parsed_function.function().ToFullyQualifiedCString()); |
| } |
| - return; |
| + return false; |
| } |
| if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| @@ -101,6 +104,13 @@ class CallSiteInliner : public FlowGraphVisitor { |
| caller_graph_->InlineCall(call, callee_graph); |
| next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); |
| + // Remove (all) push arguments of the call. |
| + for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| + PushArgumentInstr* push = call->ArgumentAt(i); |
| + push->ReplaceUsesWith(push->value()->definition()); |
| + push->RemoveFromGraph(); |
| + } |
| + |
| // Replace all the formal parameters with the actuals. |
| for (intptr_t i = 0; i < arguments->length(); ++i) { |
| Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i); |
| @@ -109,6 +119,10 @@ class CallSiteInliner : public FlowGraphVisitor { |
| param->ReplaceUsesWith((*arguments)[i]->definition()); |
| } |
| + // Replace callee's null constant with caller's null constant. |
| + callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( |
| + caller_graph_->graph_entry()->constant_null()); |
| + |
| if (FLAG_trace_inlining) { |
| OS::Print("Inlined %s\n", function.ToFullyQualifiedCString()); |
| } |
| @@ -117,6 +131,7 @@ class CallSiteInliner : public FlowGraphVisitor { |
| inlined_ = true; |
| isolate->set_long_jump_base(base); |
| isolate->set_ic_data_array(old_ic_data.raw()); |
| + return true; |
| } else { |
| Error& error = Error::Handle(); |
| error = isolate->object_store()->sticky_error(); |
| @@ -128,19 +143,84 @@ class CallSiteInliner : public FlowGraphVisitor { |
| function.ToFullyQualifiedCString(), |
| error.ToErrorCString()); |
| } |
| + return false; |
| + } |
| + } |
| + |
| + void VisitClosureCall(ClosureCallInstr* call) { |
| + if (FLAG_trace_inlining) OS::Print("Closure call\n"); |
| + // Find the closure of the callee. |
| + ASSERT(call->ArgumentCount() > 0); |
| + const CreateClosureInstr* closure = |
| + call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); |
| + if (closure == NULL) { |
| + if (FLAG_trace_inlining) { |
| + OS::Print("Inline aborted: non-closure operator.\n"); |
| + } |
| + return; |
| + } |
| + GrowableArray<Value*> arguments(call->ArgumentCount() - 1); |
| + for (int i = 1; i < call->ArgumentCount(); ++i) { |
| + arguments.Add(call->ArgumentAt(i)->value()); |
| + } |
| + TryInlining(closure->function(), &arguments, call); |
| + } |
| + |
| + void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* instr) { |
| + if (FLAG_trace_inlining) OS::Print("Polymorphic instance call\n"); |
| + InstanceCallInstr* call = instr->instance_call(); |
| + if (!call->HasICData()) { |
| + if (FLAG_trace_inlining) OS::Print("Inline aborted: has no IC data\n"); |
| + return; |
| } |
| + const ICData& ic_data = *call->ic_data(); |
|
Florian Schneider
2012/09/11 16:54:15
This can be made even simpler for monomorphic call
|
| + |
| + ASSERT(ic_data.num_args_tested() > 0); |
| + |
| + if (ic_data.NumberOfChecks() == 0) { |
| + if (FLAG_trace_inlining) OS::Print("Inline aborted: no IC checks\n"); |
| + return; |
| + } |
| + if (ic_data.NumberOfChecks() != 1) { |
|
Florian Schneider
2012/09/11 16:54:15
I think this check is not necesary since we only g
|
| + // TODO(zerny): proceed if each check has the same target? |
| + if (FLAG_trace_inlining) OS::Print("Inline aborted: non monomorphic\n"); |
| + return; |
| + } |
| + GrowableArray<intptr_t> class_ids; |
| + Function& target = Function::Handle(); |
| + ic_data.GetCheckAt(0, &class_ids, &target); |
|
Florian Schneider
2012/09/11 16:54:15
const Function& target = Function::ZoneHandle(ic_d
|
| + intptr_t class_id = class_ids[0]; |
| + if (class_id == kIllegalCid) { |
|
Florian Schneider
2012/09/11 16:54:15
Not sure if those can actually occur in type feedb
|
| + if (FLAG_trace_inlining) OS::Print("Inline aborted: invalid receiver\n"); |
| + return; |
| + } |
| + if (class_id == kDynamicCid) { |
| + if (FLAG_trace_inlining) OS::Print("Inline aborted: dynamic receiver\n"); |
| + return; |
| + } |
| + if (class_id == kSmiCid) { |
| + if (FLAG_trace_inlining) OS::Print("Inline aborted: smi receiver\n"); |
| + return; |
| + } |
| + |
| + GrowableArray<Value*> arguments(call->ArgumentCount()); |
| + for (int i = 0; i < call->ArgumentCount(); ++i) { |
| + arguments.Add(call->ArgumentAt(i)->value()); |
| + } |
| + |
| + TryInlining(target, &arguments, instr); |
| } |
| - void VisitStaticCall(StaticCallInstr* instr) { |
| + void VisitStaticCall(StaticCallInstr* call) { |
| if (FLAG_trace_inlining) OS::Print("Static call\n"); |
| - GrowableArray<Value*> arguments(instr->ArgumentCount()); |
| - for (int i = 0; i < instr->ArgumentCount(); ++i) { |
| - arguments.Add(instr->ArgumentAt(i)->value()); |
| + GrowableArray<Value*> arguments(call->ArgumentCount()); |
| + for (int i = 0; i < call->ArgumentCount(); ++i) { |
| + arguments.Add(call->ArgumentAt(i)->value()); |
| } |
| - TryInlining(instr->function(), &arguments, instr); |
| + TryInlining(call->function(), &arguments, call); |
| } |
| - bool preformed_inlining() const { return inlined_; } |
| + bool inlined() const { return inlined_; } |
| private: |
| FlowGraph* caller_graph_; |
| @@ -167,7 +247,7 @@ void FlowGraphInliner::Inline() { |
| CallSiteInliner inliner(flow_graph_); |
| inliner.VisitBlocks(); |
| - if (inliner.preformed_inlining()) { |
| + if (inliner.inlined()) { |
| if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| OS::Print("After Inlining of %s\n", flow_graph_-> |
| parsed_function().function().ToFullyQualifiedCString()); |