| Index: runtime/vm/flow_graph_inliner.cc
|
| diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
|
| index 1b4f1897784fd6c11eb13b09ad498ac9680b9cea..d853c6e62127a09719c17dfea5e15093b612fe3b 100644
|
| --- a/runtime/vm/flow_graph_inliner.cc
|
| +++ b/runtime/vm/flow_graph_inliner.cc
|
| @@ -26,18 +26,21 @@ 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,
|
| + Definition* check) {
|
| + 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 +58,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 +73,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 +105,19 @@ class CallSiteInliner : public FlowGraphVisitor {
|
| caller_graph_->InlineCall(call, callee_graph);
|
| next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
|
|
|
| + // Insert check if needed.
|
| + if (check != NULL) {
|
| + if (call->env() != NULL) call->env()->CopyTo(check);
|
| + check->InsertAfter(call->previous());
|
| + }
|
| +
|
| + // 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()->values()[i];
|
| @@ -109,6 +126,10 @@ class CallSiteInliner : public FlowGraphVisitor {
|
| param->ReplaceUsesWith((*arguments)[i]->definition());
|
| }
|
|
|
| + // Replace callees null constant with callers 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 +138,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 +150,102 @@ 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, NULL); // no check
|
| + }
|
| +
|
| + void VisitInstanceCall(InstanceCallInstr* call) {
|
| + TryInliningInstanceCall(call, call);
|
| + }
|
| +
|
| + // Needed since the instance call in a polymorphic instance call is not linked
|
| + // in the graph.
|
| + void TryInliningInstanceCall(InstanceCallInstr* call, Definition* call_defn) {
|
| + if (FLAG_trace_inlining) OS::Print("Instance call\n");
|
| + if (!call->HasICData()) {
|
| + if (FLAG_trace_inlining) OS::Print("Inline aborted: has no IC data\n");
|
| + return;
|
| + }
|
| + const ICData& ic_data = *call->ic_data();
|
| +
|
| + 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) {
|
| + // TODO(zerny): proceed if each check has the same cid?
|
| + 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);
|
| + intptr_t class_id = class_ids[0];
|
| + if (class_id == kIllegalCid) {
|
| + 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;
|
| + }
|
| +
|
| + Definition* check;
|
| + // Construct a class check for the polymorphic call.
|
| + if (call->ic_data()->GetReceiverClassIdAt(0) == kSmiCid) {
|
| + check =
|
| + new CheckSmiInstr(call->ArgumentAt(0)->value(), call->deopt_id());
|
| + } else {
|
| + const ICData& unary_checks =
|
| + ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
|
| + check =
|
| + new CheckClassInstr(call->ArgumentAt(0)->value(), call, unary_checks);
|
| + }
|
| +
|
| + GrowableArray<Value*> arguments(call->ArgumentCount());
|
| + for (int i = 0; i < call->ArgumentCount(); ++i) {
|
| + arguments.Add(call->ArgumentAt(i)->value());
|
| + }
|
| +
|
| + TryInlining(target, &arguments, call_defn, check);
|
| + }
|
| +
|
| + void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
|
| + if (FLAG_trace_inlining) OS::Print("Polymorphic ");
|
| + TryInliningInstanceCall(call->instance_call(), call);
|
| }
|
|
|
| - 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, NULL); // no check
|
| }
|
|
|
| - bool preformed_inlining() const { return inlined_; }
|
| + bool inlined() const { return inlined_; }
|
|
|
| private:
|
| FlowGraph* caller_graph_;
|
| @@ -167,7 +272,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());
|
|
|