Index: runtime/vm/flow_graph_inliner.cc |
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc |
index dff260d538c8b0ecc7e38350391225c6b75fc85b..1d4cb8b70a7f568b53cf3ee9cd8b487e52d358f9 100644 |
--- a/runtime/vm/flow_graph_inliner.cc |
+++ b/runtime/vm/flow_graph_inliner.cc |
@@ -4,10 +4,13 @@ |
#include "vm/flow_graph_inliner.h" |
+#include "vm/compiler.h" |
#include "vm/flags.h" |
#include "vm/flow_graph.h" |
#include "vm/flow_graph_builder.h" |
+#include "vm/flow_graph_optimizer.h" |
#include "vm/il_printer.h" |
+#include "vm/intrinsifier.h" |
#include "vm/longjump.h" |
#include "vm/object.h" |
#include "vm/object_store.h" |
@@ -17,6 +20,7 @@ namespace dart { |
DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); |
DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); |
DECLARE_FLAG(bool, print_flow_graph); |
+DECLARE_FLAG(int, deoptimization_counter_threshold); |
#define TRACE_INLINING(statement) \ |
do { \ |
@@ -46,10 +50,19 @@ class CallSiteInliner : public FlowGraphVisitor { |
// Assuming no optional parameters the actual/formal count should match. |
ASSERT(arguments->length() == function.num_fixed_parameters()); |
+ // Abort if the callee has an intrinsic translation. |
+ if (Intrinsifier::CanIntrinsify(function)) { |
+ TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n")); |
+ return false; |
+ } |
+ |
Isolate* isolate = Isolate::Current(); |
// Save and clear IC data. |
- const Array& old_ic_data = Array::Handle(isolate->ic_data_array()); |
+ const Array& prev_ic_data = Array::Handle(isolate->ic_data_array()); |
isolate->set_ic_data_array(Array::null()); |
+ // Save and clear deopt id. |
+ const intptr_t prev_deopt_id = isolate->deopt_id(); |
+ isolate->set_deopt_id(0); |
// Install bailout jump. |
LongJump* base = isolate->long_jump_base(); |
LongJump jump; |
@@ -59,41 +72,45 @@ class CallSiteInliner : public FlowGraphVisitor { |
ParsedFunction parsed_function(function); |
Parser::ParseFunction(&parsed_function); |
parsed_function.AllocateVariables(); |
- FlowGraphBuilder builder(parsed_function); |
+ |
+ // Load IC data for the callee. |
+ if ((function.deoptimization_counter() < |
+ FLAG_deoptimization_counter_threshold) && |
+ function.HasCode()) { |
+ const Code& unoptimized_code = |
+ Code::Handle(function.unoptimized_code()); |
+ isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); |
+ } |
// Build the callee graph. |
+ FlowGraphBuilder builder(parsed_function); |
FlowGraph* callee_graph = |
builder.BuildGraph(FlowGraphBuilder::kValueContext); |
// Abort if the callee graph contains control flow. |
if (callee_graph->preorder().length() != 2) { |
isolate->set_long_jump_base(base); |
- isolate->set_ic_data_array(old_ic_data.raw()); |
+ isolate->set_ic_data_array(prev_ic_data.raw()); |
TRACE_INLINING(OS::Print(" Bailout: control flow\n")); |
return false; |
} |
- if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
- OS::Print("Callee graph before SSA %s\n", |
- parsed_function.function().ToFullyQualifiedCString()); |
- FlowGraphPrinter printer(*callee_graph); |
- printer.PrintBlocks(); |
- } |
- |
- // Compute SSA on the callee graph. (catching bailouts) |
+ // Compute SSA on the callee graph, catching bailouts. |
callee_graph->ComputeSSA(next_ssa_temp_index_); |
+ callee_graph->ComputeUseLists(); |
+ |
+ // TODO(zerny): Do more optimization passes on the callee graph. |
+ FlowGraphOptimizer optimizer(callee_graph); |
+ optimizer.ApplyICData(); |
+ callee_graph->ComputeUseLists(); |
if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
- OS::Print("Callee graph after SSA %s\n", |
+ OS::Print("Callee graph for inlining %s\n", |
parsed_function.function().ToFullyQualifiedCString()); |
FlowGraphPrinter printer(*callee_graph); |
printer.PrintBlocks(); |
} |
- callee_graph->ComputeUseLists(); |
- |
- // TODO(zerny): Do optimization passes on the callee graph. |
- |
// TODO(zerny): If result is more than size threshold then abort. |
// TODO(zerny): If effort is less than threshold then inline recursively. |
@@ -102,14 +119,17 @@ 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. |
+ // Check that inlining maintains use lists. |
+ DEBUG_ASSERT(caller_graph_->ValidateUseLists()); |
+ |
+ // Remove 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. |
+ // Replace formal parameters with actuals. |
for (intptr_t i = 0; i < arguments->length(); ++i) { |
Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i); |
ParameterInstr* param = val->definition()->AsParameter(); |
@@ -126,14 +146,16 @@ class CallSiteInliner : public FlowGraphVisitor { |
// Build succeeded so we restore the bailout jump. |
inlined_ = true; |
isolate->set_long_jump_base(base); |
- isolate->set_ic_data_array(old_ic_data.raw()); |
+ isolate->set_deopt_id(prev_deopt_id); |
+ isolate->set_ic_data_array(prev_ic_data.raw()); |
return true; |
} else { |
Error& error = Error::Handle(); |
error = isolate->object_store()->sticky_error(); |
isolate->object_store()->clear_sticky_error(); |
isolate->set_long_jump_base(base); |
- isolate->set_ic_data_array(old_ic_data.raw()); |
+ isolate->set_deopt_id(prev_deopt_id); |
+ isolate->set_ic_data_array(prev_ic_data.raw()); |
TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
return false; |
} |
@@ -199,6 +221,10 @@ void FlowGraphInliner::Inline() { |
return; |
} |
+ TRACE_INLINING(OS::Print( |
+ "Inlining calls in %s\n", |
+ flow_graph_->parsed_function().function().ToCString())); |
+ |
if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
OS::Print("Before Inlining of %s\n", flow_graph_-> |
parsed_function().function().ToFullyQualifiedCString()); |
@@ -206,9 +232,6 @@ void FlowGraphInliner::Inline() { |
printer.PrintBlocks(); |
} |
- TRACE_INLINING(OS::Print( |
- "Inlining calls in %s\n", |
- flow_graph_->parsed_function().function().ToCString())); |
CallSiteInliner inliner(flow_graph_); |
inliner.VisitBlocks(); |